Compare commits

...

25 Commits

Author SHA1 Message Date
Aircoookie
82d40f60f1 Release of WLED 0.7.1
Merge dev to master
2018-08-11 23:05:11 +02:00
cschwinne
1d4d885276 Release of WLED 0.7.1 to dev branch
Added E1.31 support
Added more realtime options
Attempted to fix welcome page not showing on fresh install
2018-08-11 22:59:37 +02:00
cschwinne
ed3557ffca Fixed Exception 28 loop on fresh install
Removed legacy binaries folder
2018-08-05 19:22:48 +02:00
cschwinne
1c3878fcb0 Added blynk UI updates 2018-07-29 14:03:02 +02:00
cschwinne
b3dcb9fe6c Fixed ESP32 resetting upon opening wifi settings 2018-07-22 21:21:18 +02:00
cschwinne
0462755922 further optimization 2018-07-22 14:55:10 +02:00
cschwinne
415dfd2750 Continued optimizing strings 2018-07-21 23:21:07 +02:00
cschwinne
72f203e4fa Started optimizing code by converting String to char* 2018-07-20 19:35:31 +02:00
cschwinne
4e3c83af94 Added Blynk support
Fixed AutoRGBW not disabling white slider in UI
Fixed possible UDP buffer out of bounds
2018-07-16 11:50:09 +02:00
Aircoookie
65a0f60257 Merge pull request #27 from Aircoookie/development
Development
2018-06-24 01:38:12 +02:00
cschwinne
094bdf02c4 Release of v0.7.0
Substantial optimizations of mobile UI
Added option to save current preset cycle as boot default
Added option not to use first LED in strip
Realtime UI error now includes source IP address
Removed /down and /cleareeprom pages
Fixed bug (turning receiveDirect off would crash on UDP packet)
2018-06-24 01:20:15 +02:00
cschwinne
5d8d12bc89 First commit to development branch
Added AutoRGBW feature
Nightlight turns off if its target brightness is set
2018-05-31 19:26:16 +02:00
cschwinne
89b9fd8a45 Mobile UI by StormPie added 2018-05-22 21:11:19 +02:00
cschwinne
ce1ba3bc2c Added Hyperion support on UDP port 19446 2018-05-18 23:24:47 +02:00
cschwinne
3afb499930 Changed preset cycle API format
Added secondary color transition
Added option to have UI while receiving realtime
Fixed mDNS not working
Fixed Arduino OTA not working when locked but enabled
2018-05-10 19:55:58 +02:00
cschwinne
356ff57005 Added more usermod functions 2018-04-24 12:03:25 +02:00
cschwinne
16ce67057d Updated version in readme
(I always forget this!)
2018-04-15 18:49:47 +02:00
cschwinne
4c9dc739ae Release of v0.6.4
Added Limited support of up to 1200 (ESP8266) or 600 (ESP32) LEDs
Changed &ND API call to activate Nightight without requiring NL
2018-04-15 15:27:54 +02:00
cschwinne
a665607fac Finished Dynamic LED drivers 2018-04-14 18:56:35 +02:00
cschwinne
7f5671f975 Started with wrapper to support dynamic LED counts and pixel features 2018-04-13 00:28:29 +02:00
cschwinne
ee6676cd89 Release of v0.6.3
Added Preset Cycle feature
Added Transition Time API call
Added Adalight serial ambilight protocol
Added DRGB and DRGBW UDP direct-drive protocols
Improved transition flickering
Easter eggs are eaten now
2018-04-11 23:50:35 +02:00
cschwinne
df05754872 Updated readme 2018-04-01 00:15:14 +02:00
cschwinne
72223c7e42 Release of v0.6.2
Added /easter joke subpage
Added Easter (6) effect
Merged Single and Multi Dynamic (7) effects
Added Easter theme
Added North Korea timezone
2018-04-01 00:08:50 +02:00
cschwinne
ba04aa7fef Release of v0.6.1
Added 3 effects (Android (27), Gradient (46) and Loading (47))
Support effect intensity setting for 4 additional effects
(Twinkle Fade, Twinkle RF, Sparkle Inv and Sparkle Inv+)
Removed 3 unused and duplicate effects
2018-03-18 23:16:53 +01:00
cschwinne
c855b8397a Fixed Hue always applying brightness bug 2018-03-15 19:54:11 +01:00
69 changed files with 7725 additions and 1002 deletions

View File

@@ -1,22 +0,0 @@
### Where are the new binaries?
From v0.5.0 on forward, the GitHub [releases](https://github.com/Aircoookie/WLED/releases) system will be used for binaries.
### What binary should I choose?
Currently WLED supports the ESP8266 and a very early, experimental version of ESP32 support.
Be sure to choose the correct binary for your platform and LED type.
- Do you have a standard RGB WS2812B NeoPixel strip?
--> Use wled05dev_XXXXXXX_RGB_PLATFORM.bin
- Do you have an RGBW SK6812 strip (half of the LED is white)?
--> Use wled05dev_XXXXXXX_RGBW_PLATFORM.bin
- Do you have a Cronixie clock set by Diamex?
--> Use wled05dev_XXXXXXX_CRONIXIE_PLATFORM.bin
### What about wled03 and wled04?
These are legacy releases only for the ESP8266. They don't include the latest features and may have unfixed bugs - only use them if the new wled05dev test builds don't work for you!

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,30 +1,30 @@
## Welcome to my project WLED!
WLED is a fast and (relatively) secure implementation of an ESP8266 webserver to control NeoPixel (WS2812B) LEDs!
Now also with experimental ESP32 support.
WLED is a fast and (relatively) secure implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B) LEDs!
### Features: (V0.6.0)
### Features: (V0.7.1)
- RGB, HSB, and brightness sliders
- All new, mobile-friendly web UI!
- Settings page - configuration over network
- Access Point and station mode - automatic failsafe AP
- WS2812FX library integrated for over 50 special effects!
- Support of Blynk IoT cloud
- WS2812FX library integrated for over 50 special effects (+Custom Theater Chase)!
- Secondary color support lets you use even more effect combinations
- Alexa smart home device server (including dimming)
- Beta syncronization to Philips hue lights
- Support for RGBW strips
- 25 user presets! Save your favorite colors and effects and apply them easily!
- 25 user presets! Save colors and effects and apply them easily! Supports cycling through them.
- HTTP request API for simple integration
- Macro functions to automatically execute API calls
- Nightlight function (gradually dims down)
- Notifier function (multiple ESPs sync color via UDP broadcast)
- Support for power pushbutton
- Custom Theater Chase
- Support for the Adalight serial ambilight protocol!
- Full OTA software update capability (HTTP and ArduinoOTA)
- Password protected OTA page for added security (OTA lock)
- NTP and configurable analog clock function
- Support for the Cronixie Clock kit by Diamex
- Realtime UDP Packet Control (WARLS) possible
- Client HTML UI controlled, customizable themes
- Realtime UDP Packet Control (E1.31, Hyperion, WARLS, DRGB, DRGBW)
### Quick start guide and documentation:

176
wled00/NpbWrapper.h Normal file
View File

@@ -0,0 +1,176 @@
//this code is a modified version of https://github.com/Makuna/NeoPixelBus/issues/103
//#define WORKAROUND_ESP32_BITBANG
//see https://github.com/Aircoookie/WLED/issues/2 for flicker free ESP32 support
//uncomment this if red and green are swapped
//#define SWAPRG
//automatically uses the right driver method for each platform
#ifdef ARDUINO_ARCH_ESP32
#ifdef WORKAROUND_ESP32_BITBANG
#define PIXELMETHOD NeoEsp32BitBangWs2813Method
#else
#define PIXELMETHOD NeoEsp32RmtWS2813_V3Method
#endif
#else
#define PIXELMETHOD NeoEsp8266Uart800KbpsMethod
#endif
//handle swapping Red and Green automatically
#ifdef SWAPRG
#define PIXELFEATURE3 NeoRgbFeature
#define PIXELFEATURE4 NeoRgbwFeature
#else
#define PIXELFEATURE3 NeoGrbFeature
#define PIXELFEATURE4 NeoGrbwFeature
#endif
#include <NeoPixelBrightnessBus.h>
enum NeoPixelType
{
NeoPixelType_None = 0,
NeoPixelType_Grb = 1,
NeoPixelType_Grbw = 2,
NeoPixelType_End = 3
};
class NeoPixelWrapper
{
public:
NeoPixelWrapper() :
// initialize each member to null
_pGrb(NULL),
_pGrbw(NULL),
_type(NeoPixelType_None)
{
}
~NeoPixelWrapper()
{
cleanup();
}
void Begin(NeoPixelType type, uint16_t countPixels, uint8_t pin)
{
cleanup();
_type = type;
switch (_type) {
case NeoPixelType_Grb:
_pGrb = new NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>(countPixels, pin);
_pGrb->Begin();
break;
case NeoPixelType_Grbw:
_pGrbw = new NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>(countPixels, pin);
_pGrbw->Begin();
break;
}
}
void Show()
{
#ifdef ARDUINO_ARCH_ESP32
#ifdef WORKAROUND_ESP32_BITBANG
delay(1);
portDISABLE_INTERRUPTS(); //this is a workaround to prevent flickering (see https://github.com/adafruit/Adafruit_NeoPixel/issues/139)
#endif
#endif
switch (_type) {
case NeoPixelType_Grb: _pGrb->Show(); break;
case NeoPixelType_Grbw: _pGrbw->Show(); break;
}
#ifdef ARDUINO_ARCH_ESP32
#ifdef WORKAROUND_ESP32_BITBANG
portENABLE_INTERRUPTS();
#endif
#endif
}
bool CanShow() const
{
switch (_type) {
case NeoPixelType_Grb: _pGrb->CanShow(); break;
case NeoPixelType_Grbw: _pGrbw->CanShow(); break;
}
}
void SetPixelColor(uint16_t indexPixel, RgbColor color)
{
switch (_type) {
case NeoPixelType_Grb: _pGrb->SetPixelColor(indexPixel, color); break;
case NeoPixelType_Grbw:_pGrbw->SetPixelColor(indexPixel, color); break;
}
}
void SetPixelColor(uint16_t indexPixel, RgbwColor color)
{
switch (_type) {
case NeoPixelType_Grb: _pGrbw->SetPixelColor(indexPixel, color); break;
case NeoPixelType_Grbw: _pGrbw->SetPixelColor(indexPixel, color); break;
}
}
void SetBrightness(byte b)
{
switch (_type) {
case NeoPixelType_Grb: _pGrb->SetBrightness(b); break;
case NeoPixelType_Grbw:_pGrbw->SetBrightness(b); break;
}
}
RgbColor GetPixelColor(uint16_t indexPixel) const
{
switch (_type) {
case NeoPixelType_Grb: return _pGrb->GetPixelColor(indexPixel); break;
case NeoPixelType_Grbw: /*doesn't support it so we don't return it*/ break;
}
return 0;
}
// NOTE: Due to feature differences, some support RGBW but the method name
// here needs to be unique, thus GetPixeColorRgbw
RgbwColor GetPixelColorRgbw(uint16_t indexPixel) const
{
switch (_type) {
case NeoPixelType_Grb: return _pGrb->GetPixelColor(indexPixel); break;
case NeoPixelType_Grbw: return _pGrbw->GetPixelColor(indexPixel); break;
}
return 0;
}
void ClearTo(RgbColor color)
{
switch (_type) {
case NeoPixelType_Grb: _pGrb->ClearTo(color); break;
case NeoPixelType_Grbw:_pGrbw->ClearTo(color); break;
}
}
void ClearTo(RgbwColor color)
{
switch (_type) {
case NeoPixelType_Grb: break;
case NeoPixelType_Grbw:_pGrbw->ClearTo(color); break;
}
}
private:
NeoPixelType _type;
// have a member for every possible type
NeoPixelBrightnessBus<PIXELFEATURE3,PIXELMETHOD>* _pGrb;
NeoPixelBrightnessBus<PIXELFEATURE4,PIXELMETHOD>* _pGrbw;
void cleanup()
{
switch (_type) {
case NeoPixelType_Grb: delete _pGrb ; _pGrb = NULL; break;
case NeoPixelType_Grbw: delete _pGrbw; _pGrbw = NULL; break;
}
}
};

View File

@@ -37,9 +37,9 @@
#define CALL_MODE(n) (this->*_mode[n])();
void WS2812FX::init() {
void WS2812FX::init(bool supportWhite, uint16_t countPixels, uint8_t pin,bool skipFirst) {
begin(supportWhite,countPixels,pin,skipFirst);
for (int i=0; i < _led_count; i++) _locked[i] = false;
begin();
WS2812FX::setBrightness(_brightness);
show();
}
@@ -66,6 +66,7 @@ void WS2812FX::start() {
_counter_mode_step = 0;
_mode_last_call_time = 0;
_running = true;
show();
}
void WS2812FX::stop() {
@@ -79,16 +80,14 @@ void WS2812FX::setMode(byte m) {
_mode_last_call_time = 0;
_mode_index = constrain(m, 0, MODE_COUNT-1);
_mode_color = _color;
_mode_var1 = 0;
setBrightness(_brightness);
strip_off_respectLock();
}
void WS2812FX::setSpeed(byte s) {
_counter_mode_call = 0;
_counter_mode_step = 0;
_mode_last_call_time = 0;
_speed = constrain(s, SPEED_MIN, SPEED_MAX);
strip_off_respectLock();
}
void WS2812FX::increaseSpeed(byte s) {
@@ -131,7 +130,6 @@ void WS2812FX::setColor(uint32_t c) {
void WS2812FX::setSecondaryColor(uint32_t c) {
_color_sec = c;
_mode_color_sec = _color;
if (_cronixieMode) _cronixieSecMultiplier = getSafePowerMultiplier(900, 100, c, _brightness);
setBrightness(_brightness);
}
@@ -322,31 +320,35 @@ void WS2812FX::mode_random_color(void) {
/*
* Lights every LED in a random color. Changes one random LED after the other
* to another random color.
* Lights some pastel colors
*/
void WS2812FX::mode_single_dynamic(void) {
if(_counter_mode_call == 0) {
for(uint16_t i=0; i < _led_count; i++) {
if (!_locked[i])
setPixelColor(i, color_wheel(random(256)));
}
}
int ran = random(_led_count);
if (!_locked[ran])
setPixelColor(ran, color_wheel(random(256)));
show();
_mode_delay = 10 + ((5000 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX);
void WS2812FX::mode_easter(void) {
//uint32_t cols[]{0x00F7ECC5,0x00F8D5C7,0x00F9E2E7,0x00BED9D4,0x00F7ECC5,0x00F8D5C7,0x00F9E2E7};
uint32_t cols[]{0x00FF8040,0x00E5D241,0x0077FF77,0x0077F0F0,0x00FF8040,0x00E5D241,0x0077FF77};
mode_colorful_internal(cols);
}
/*
* Lights multiple random leds in a random color (higher intensity, more updates)
*/
void WS2812FX::mode_multi_dynamic(void) {
for(uint16_t i=0; i < _led_count; i++) {
if (!_locked[i] && random(256)<=_intensity)
setPixelColor(i, color_wheel(random(256)));
void WS2812FX::mode_dynamic(void) {
if(_counter_mode_call == 0) {
for(uint16_t i=0; i < _led_count; i++) {
if (!_locked[i])
setPixelColor(i, color_wheel(random(256)));
}
}
if (_intensity > 0) //multi dynamic
{
for(uint16_t i=0; i < _led_count; i++) {
if (!_locked[i] && random(256)<_intensity)
setPixelColor(i, color_wheel(random(256)));
}
} else { //single dynamic
int ran = random(_led_count);
if (!_locked[ran])
setPixelColor(ran, color_wheel(random(256)));
}
show();
_mode_delay = 100 + ((5000 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX);
@@ -384,7 +386,7 @@ void WS2812FX::mode_breath(void) {
setPixelColor(i, _color); // set all LEDs to selected color
}
int b = map(breath_brightness, 0, 255, 0, _brightness); // keep brightness below brightness set by user
NeoPixelBrightnessBus::SetBrightness(b); // set new brightness to leds
bus->SetBrightness(b); // set new brightness to leds
show();
_mode_color = breath_brightness; // we use _mode_color to store the brightness
@@ -625,7 +627,7 @@ void WS2812FX::mode_twinkle_fade(void) {
setPixelColor(i, px_r, px_g, px_b, px_w);
}
if(random(3) == 0) {
if(random(256) < _intensity) {
int ran = random(_led_count);
if (!_locked[ran])
setPixelColor(ran, _mode_color);
@@ -673,7 +675,7 @@ void WS2812FX::mode_flash_sparkle(void) {
setPixelColor(i, _color);
}
if(random(10) == 7) {
if(random(256) <= _intensity) {
int ran = random(_led_count);
if (!_locked[ran])
setPixelColor(ran , _color_sec);
@@ -696,7 +698,7 @@ void WS2812FX::mode_hyper_sparkle(void) {
setPixelColor(i, _color);
}
if(random(10) < 4) {
if(random(256) <= _intensity) {
for(uint16_t i=0; i < maxval(1, _led_count/3); i++) {
int ran = random(_led_count);
if (!_locked[ran])
@@ -802,9 +804,64 @@ void WS2812FX::mode_blink_rainbow(void) {
/*
* _color running on _color_sec.
* Android loading circle
*/
void WS2812FX::mode_chase_white(void) {
void WS2812FX::mode_android(void) {
if (_counter_mode_call == 0) _mode_color = 0; //we use modecolor as bool
for(uint16_t i=0; i < _led_count; i++) {
if (!_locked[i])
setPixelColor(i, _color_sec);
}
uint16_t a = _counter_mode_step;
if (_mode_var1 > ((float)_intensity/255.0)*(float)_led_count)
{
_mode_color = 1;
} else
{
if (_mode_var1 < 2) _mode_color = 0;
}
if (_mode_color == 0)
{
if (_counter_mode_call %3 == 1) {a++;}
else {_mode_var1++;}
} else
{
a++;
if (_counter_mode_call %3 != 1) _mode_var1--;
}
if (a >= _led_count) a = 0;
if (a +_mode_var1 <= _led_count)
{
for(int i = a; i < a+_mode_var1; i++) {
if (!_locked[i])
setPixelColor(i, _color);
}
} else
{
for(int i = a; i < _led_count; i++) {
if (!_locked[i])
setPixelColor(i, _color);
}
for(int i = 0; i < _mode_var1 - (_led_count - a); i++) {
if (!_locked[i])
setPixelColor(i, _color);
}
}
_counter_mode_step = a;
show();
_mode_delay = 3 + ((8 * (uint32_t)(SPEED_MAX - _speed)) / _led_count);
}
/*
* _color_sec running on _color.
*/
void WS2812FX::mode_chase_color(void) {
for(uint16_t i=0; i < _led_count; i++) {
if (!_locked[i])
setPixelColor(i, _color_sec);
@@ -823,28 +880,6 @@ void WS2812FX::mode_chase_white(void) {
}
/*
* _color_sec running on _color.
*/
void WS2812FX::mode_chase_color(void) {
for(uint16_t i=0; i < _led_count; i++) {
if (!_locked[i])
setPixelColor(i, _color);
}
uint16_t n = _counter_mode_step;
uint16_t m = (_counter_mode_step + 1) % _led_count;
if (!_locked[n])
setPixelColor(n, _color_sec);
if (!_locked[m])
setPixelColor(m, _color_sec);
show();
_counter_mode_step = (_counter_mode_step + 1) % _led_count;
_mode_delay = 10 + ((30 * (uint32_t)(SPEED_MAX - _speed)) / _led_count);
}
/*
* color_sec running followed by random color.
*/
@@ -991,14 +1026,20 @@ void WS2812FX::mode_chase_rainbow_white(void) {
_mode_delay = 10 + ((30 * (uint32_t)(SPEED_MAX - _speed)) / _led_count);
}
/*
* Red - Amber - Green - Blue lights running
*/
void WS2812FX::mode_colorful(void) {
uint32_t cols[]{0x00FF0000,0x00EEBB00,0x0000EE00,0x000077CC,0x00FF0000,0x00EEBB00,0x0000EE00};
mode_colorful_internal(cols);
}
/*
* Common function for 4-color-running (Colorful, easter)
*/
void WS2812FX::mode_colorful_internal(uint32_t cols[]) {
int i = 0;
for (i; i < _led_count-3 ; i+=4)
for (i; i < _led_count ; i+=4)
{
if(!_locked[i])setPixelColor(i, cols[_counter_mode_step]);
if(!_locked[i+1])setPixelColor(i+1, cols[_counter_mode_step+1]);
@@ -1024,7 +1065,7 @@ void WS2812FX::mode_colorful(void) {
show();
if (_speed > SPEED_MIN) _counter_mode_step++; //static if lowest speed
if (_counter_mode_step >3) _counter_mode_step = 0;
_mode_delay = 100 + (25 * (uint32_t)(SPEED_MAX - _speed));
_mode_delay = 50 + (15 * (uint32_t)(SPEED_MAX - _speed));
}
@@ -1315,27 +1356,17 @@ void WS2812FX::mode_merry_christmas(void) {
_mode_delay = 50 + ((75 * (uint32_t)(SPEED_MAX - _speed)) / _led_count);
}
/*
* Random flickering.
*/
void WS2812FX::mode_fire_flicker(void) {
mode_fire_flicker_int(3);
}
/*
* Random flickering, less intesity.
*/
void WS2812FX::mode_fire_flicker_soft(void) {
mode_fire_flicker_int(6);
}
void WS2812FX::mode_fire_flicker_int(int rev_intensity)
void WS2812FX::mode_fire_flicker(void)
{
byte p_w = (_color & 0xFF000000) >> 24;
byte p_r = (_color & 0x00FF0000) >> 16;
byte p_g = (_color & 0x0000FF00) >> 8;
byte p_b = (_color & 0x000000FF) >> 0;
byte flicker_val = maxval(p_r,maxval(p_g, maxval(p_b, p_w)))/rev_intensity;
byte flicker_val = maxval(p_r,maxval(p_g, maxval(p_b, p_w)))/(((256-_intensity)/16)+1);
for(uint16_t i=0; i < _led_count; i++)
{
int flicker = random(0,flicker_val);
@@ -1351,30 +1382,90 @@ void WS2812FX::mode_fire_flicker_int(int rev_intensity)
setPixelColor(i,r1,g1,b1,w1);
}
show();
_mode_delay = 10 + ((500 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX);
_mode_delay = 10 + ((400 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX);
}
void WS2812FX::mode_fade_down(void)
{
for(uint16_t i=0; i < _led_count; i++) {
uint32_t px_rgb = getPixelColor(i);
/*
* Gradient run
*/
void WS2812FX::mode_gradient(void) {
byte p_w = (_color & 0xFF000000) >> 24;
byte p_r = (_color & 0x00FF0000) >> 16;
byte p_g = (_color & 0x0000FF00) >> 8;
byte p_b = (_color & 0x000000FF) >> 0;
byte p_w2 = (_color_sec & 0xFF000000) >> 24;
byte p_r2 = (_color_sec & 0x00FF0000) >> 16;
byte p_g2 = (_color_sec & 0x0000FF00) >> 8;
byte p_b2 = (_color_sec & 0x000000FF) >> 0;
byte nw,nr,ng,nb;
float per,val; //0.0 = sec 1.0 = pri
float brd = _intensity/2; if (brd <1.0) brd = 1.0;
int pp = _counter_mode_step;
int p1 = pp-_led_count;
int p2 = pp+_led_count;
byte px_w = (px_rgb & 0xFF000000) >> 24;
byte px_r = (px_rgb & 0x00FF0000) >> 16;
byte px_g = (px_rgb & 0x0000FF00) >> 8;
byte px_b = (px_rgb & 0x000000FF) >> 0;
// fade out (divide by 2)
px_w = px_w >> 1;
px_r = px_r >> 1;
px_g = px_g >> 1;
px_b = px_b >> 1;
if (!_locked[i])
setPixelColor(i, px_r, px_g, px_b, px_w);
}
show();
for(uint16_t i=0; i < _led_count; i++)
{
if (!_locked[i])
{
val = minval(abs(pp-i),minval(abs(p1-i),abs(p2-i)));
per = val/brd;
if (per >1.0) per = 1.0;
nw = p_w+((p_w2 - p_w)*per);
nr = p_r+((p_r2 - p_r)*per);
ng = p_g+((p_g2 - p_g)*per);
nb = p_b+((p_b2 - p_b)*per);
setPixelColor(i,nr,ng,nb,nw);
}
}
_mode_delay = 100 + ((100 * (uint32_t)(SPEED_MAX - _speed)) / SPEED_MAX);
show();
_counter_mode_step++;
if (_counter_mode_step >= _led_count) _counter_mode_step = 0;
if (_speed == 0) _counter_mode_step = _led_count >> 1;
_mode_delay = 7 + ((25 * (uint32_t)(SPEED_MAX - _speed)) / _led_count);
}
/*
* Gradient run with hard transition
*/
void WS2812FX::mode_loading(void) {
byte p_w = (_color & 0xFF000000) >> 24;
byte p_r = (_color & 0x00FF0000) >> 16;
byte p_g = (_color & 0x0000FF00) >> 8;
byte p_b = (_color & 0x000000FF) >> 0;
byte p_w2 = (_color_sec & 0xFF000000) >> 24;
byte p_r2 = (_color_sec & 0x00FF0000) >> 16;
byte p_g2 = (_color_sec & 0x0000FF00) >> 8;
byte p_b2 = (_color_sec & 0x000000FF) >> 0;
byte nw,nr,ng,nb;
float per,val; //0.0 = sec 1.0 = pri
float brd = _intensity; if (brd <1.0) brd = 1.0;
int pp = _counter_mode_step;
int p1 = pp+_led_count;
for(uint16_t i=0; i < _led_count; i++)
{
if (!_locked[i])
{
pp = _counter_mode_step;
if (i > pp) pp+=_led_count;
val = abs(pp-i);
per = val/brd;
if (per >1.0) per = 1.0;
nw = p_w+((p_w2 - p_w)*per);
nr = p_r+((p_r2 - p_r)*per);
ng = p_g+((p_g2 - p_g)*per);
nb = p_b+((p_b2 - p_b)*per);
setPixelColor(i,nr,ng,nb,nw);
}
}
show();
_counter_mode_step++;
if (_counter_mode_step >= _led_count) _counter_mode_step = 0;
if (_speed == 0) _counter_mode_step = _led_count -1;
_mode_delay = 7 + ((25 * (uint32_t)(SPEED_MAX - _speed)) / _led_count);
}
/*
@@ -1805,11 +1896,6 @@ void WS2812FX::unlockAll()
_locked[x] = false;
}
void WS2812FX::setLedCount(uint16_t i)
{
_led_count = i;
}
void WS2812FX::setFastUpdateMode(bool y)
{
_fastStandard = y;
@@ -1839,16 +1925,12 @@ void WS2812FX::setCronixieDigits(byte d[])
}
}
double WS2812FX::getPowerEstimate(byte leds, uint32_t c, byte b)
double WS2812FX::getPowerEstimate(uint16_t leds, uint32_t c, byte b)
{
double _mARequired = 100; //ESP power
double _mul = (double)b/255;
double _sum = ((c & 0xFF000000) >> 24) + ((c & 0x00FF0000) >> 16) + ((c & 0x0000FF00) >> 8) + ((c & 0x000000FF) >> 0);
#ifdef RGBW
_sum /= 1024;
#else
_sum /= 768;
#endif
_sum /= (_rgbwMode)? 1024:768;
double _mAPerLed = 50*(_mul*_sum);
_mARequired += leds*_mAPerLed;
return _mARequired;
@@ -1859,7 +1941,7 @@ double WS2812FX::getPowerEstimate(byte leds, uint32_t c, byte b)
//It is NOT guaranteed to stay within the safeAmps margin.
//Stay safe with high amperage and have a reasonable safety margin!
//I am NOT to be held liable for burned down garages!
double WS2812FX::getSafePowerMultiplier(double safeMilliAmps, byte leds, uint32_t c, byte b)
double WS2812FX::getSafePowerMultiplier(double safeMilliAmps, uint16_t leds, uint32_t c, byte b)
{
double _mARequired = getPowerEstimate(leds,c,b);
if (_mARequired > safeMilliAmps)
@@ -1876,7 +1958,7 @@ void WS2812FX::setCCIndex1(byte i1)
_counter_ccStep = 0;
}
void WS2812FX::setCCIndex2(byte i2)
void WS2812FX::setCCIndex2(uint16_t i2)
{
if (i2 > _cc_i1) _cc_i2 = i2;
if (_cc_i2 >= _led_count) _cc_i2 = _led_count-1;
@@ -1921,7 +2003,7 @@ void WS2812FX::setCCFE(bool fe)
_counter_ccStep = 0;
}
void WS2812FX::setCustomChase(byte i1, byte i2, byte is, byte np, byte ns, byte stp, bool fs, bool fe)
void WS2812FX::setCustomChase(byte i1, uint16_t i2, byte is, byte np, byte ns, byte stp, bool fs, bool fe)
{
setCCIndex1(i1);
setCCIndex2(i2);
@@ -1936,11 +2018,13 @@ void WS2812FX::setCustomChase(byte i1, byte i2, byte is, byte np, byte ns, byte
//Added for quick NeoPixelBus compatibility with Adafruit syntax
void WS2812FX::setPixelColorRaw(uint16_t i, byte r, byte g, byte b, byte w)
{
#ifdef RGBW
NeoPixelBrightnessBus::SetPixelColor(i, RgbwColor(r,g,b,w));
#else
NeoPixelBrightnessBus::SetPixelColor(i, RgbColor(r,g,b));
#endif
if (_rgbwMode)
{
bus->SetPixelColor(i, RgbwColor(r,g,b,w));
} else
{
bus->SetPixelColor(i, RgbColor(r,g,b));
}
}
void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
@@ -1948,11 +2032,14 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
if (_reverseMode) i = _led_count - 1 -i;
if (!_cronixieMode)
{
#ifdef RGBW
NeoPixelBrightnessBus::SetPixelColor(i, RgbwColor(r,g,b,w));
#else
NeoPixelBrightnessBus::SetPixelColor(i, RgbColor(r,g,b));
#endif
if (_skipFirstMode) {i++;if(i==1)setPixelColorRaw(0,0,0,0,0);}
if (_rgbwMode)
{
bus->SetPixelColor(i, RgbwColor(r,g,b,w));
} else
{
bus->SetPixelColor(i, RgbColor(r,g,b));
}
} else {
if(i>6)return;
byte o = 10*i;
@@ -1964,27 +2051,27 @@ void WS2812FX::setPixelColor(uint16_t i, byte r, byte g, byte b, byte w)
byte wCorr = (int)(((double)((_color_sec>>24) & 0xFF))*_cronixieSecMultiplier);
for (int j=o; j< o+19; j++)
{
setPixelColorRaw(j,rCorr,gCorr,bCorr,wCorr);
setPixelColorRaw((_skipFirstMode)?j+1:j,rCorr,gCorr,bCorr,wCorr);
}
} else
{
for (int j=o; j< o+19; j++)
{
setPixelColorRaw(j,0,0,0,0);
setPixelColorRaw((_skipFirstMode)?j+1:j,0,0,0,0);
}
}
switch(_cronixieDigits[i])
{
case 0: setPixelColorRaw(o+5,r,g,b,w); break;
case 1: setPixelColorRaw(o+0,r,g,b,w); break;
case 2: setPixelColorRaw(o+6,r,g,b,w); break;
case 3: setPixelColorRaw(o+1,r,g,b,w); break;
case 4: setPixelColorRaw(o+7,r,g,b,w); break;
case 5: setPixelColorRaw(o+2,r,g,b,w); break;
case 6: setPixelColorRaw(o+8,r,g,b,w); break;
case 7: setPixelColorRaw(o+3,r,g,b,w); break;
case 8: setPixelColorRaw(o+9,r,g,b,w); break;
case 9: setPixelColorRaw(o+4,r,g,b,w); break;
case 0: setPixelColorRaw((_skipFirstMode)?o+6:o+5,r,g,b,w); break;
case 1: setPixelColorRaw((_skipFirstMode)?o+1:o+0,r,g,b,w); break;
case 2: setPixelColorRaw((_skipFirstMode)?o+7:o+6,r,g,b,w); break;
case 3: setPixelColorRaw((_skipFirstMode)?o+2:o+1,r,g,b,w); break;
case 4: setPixelColorRaw((_skipFirstMode)?o+8:o+7,r,g,b,w); break;
case 5: setPixelColorRaw((_skipFirstMode)?o+3:o+2,r,g,b,w); break;
case 6: setPixelColorRaw((_skipFirstMode)?o+9:o+8,r,g,b,w); break;
case 7: setPixelColorRaw((_skipFirstMode)?o+4:o+3,r,g,b,w); break;
case 8: setPixelColorRaw((_skipFirstMode)?o+10:o+9,r,g,b,w); break;
case 9: setPixelColorRaw((_skipFirstMode)?o+5:o+4,r,g,b,w); break;
default: break;
}
}
@@ -2021,62 +2108,57 @@ uint32_t WS2812FX::getPixelColor(uint16_t i)
default: return 0;
}
}
#ifdef RGBW
RgbwColor lColor = NeoPixelBrightnessBus::GetPixelColor(i);
return lColor.W*16777216 + lColor.R*65536 + lColor.G*256 + lColor.B;
#else
RgbColor lColor = NeoPixelBrightnessBus::GetPixelColor(i);
return lColor.R*65536 + lColor.G*256 + lColor.B;
#endif
if (_rgbwMode)
{
RgbwColor lColor = bus->GetPixelColorRgbw(i);
return lColor.W*16777216 + lColor.R*65536 + lColor.G*256 + lColor.B;
} else {
RgbColor lColor = bus->GetPixelColor(i);
return lColor.R*65536 + lColor.G*256 + lColor.B;
}
}
void WS2812FX::setBrightness(byte b)
{
_brightness = constrain(b, BRIGHTNESS_MIN, BRIGHTNESS_MAX);
NeoPixelBrightnessBus::SetBrightness(_brightness);
show();
bus->SetBrightness(_brightness);
if (_mode_last_call_time + _mode_delay > millis()+50 || b == 0) show(); //only update right away if long time until next refresh
}
void WS2812FX::show()
{
#ifdef ARDUINO_ARCH_ESP32
#ifdef WORKAROUND_ESP32_BITBANG
delay(1);
portDISABLE_INTERRUPTS(); //this is a workaround to prevent flickering (see https://github.com/adafruit/Adafruit_NeoPixel/issues/139)
#endif
#endif
NeoPixelBrightnessBus::Show();
#ifdef ARDUINO_ARCH_ESP32
#ifdef WORKAROUND_ESP32_BITBANG
portENABLE_INTERRUPTS();
#endif
#endif
bus->Show();
}
void WS2812FX::clear()
{
#ifdef RGBW
NeoPixelBrightnessBus::ClearTo(RgbwColor(0));
#else
NeoPixelBrightnessBus::ClearTo(RgbColor(0));
#endif
bus->ClearTo(RgbColor(0));
}
void WS2812FX::begin()
void WS2812FX::begin(bool supportWhite, uint16_t countPixels, uint8_t pin, bool skipFirst)
{
NeoPixelBrightnessBus::Begin();
if (supportWhite == _rgbwMode && countPixels == _led_count && _locked != NULL) return;
_rgbwMode = supportWhite;
_skipFirstMode = skipFirst;
_led_count = countPixels;
_cc_i2 = _led_count -1;
if (_skipFirstMode) _led_count++;
uint8_t ty = 1;
if (supportWhite) ty =2;
bus->Begin((NeoPixelType)ty, _led_count, pin);
if (_locked != NULL) delete _locked;
_locked = new bool[_led_count];
}
//For some reason min and max are not declared here
byte WS2812FX::minval (byte v, byte w)
uint16_t WS2812FX::minval (uint16_t v, uint16_t w)
{
if (w > v) return v;
return w;
}
byte WS2812FX::maxval (byte v, byte w)
uint16_t WS2812FX::maxval (uint16_t v, uint16_t w)
{
if (w > v) return w;
return v;

View File

@@ -1,25 +1,4 @@
//#define RGBW
#define PIN 2 //strip pin. Only change for ESP32
#define WORKAROUND_ESP32_BITBANG
//see https://github.com/Aircoookie/WLED/issues/2 for flicker free ESP32 support
//automatically uses the right driver method for each platform
#ifdef ARDUINO_ARCH_ESP32
#ifdef WORKAROUND_ESP32_BITBANG
#define PIXELMETHOD NeoEsp32BitBangWs2813Method
#else
#define PIXELMETHOD NeoEsp32RmtWS2813_V3Method
#endif
#else
#define PIXELMETHOD NeoEsp8266Uart800KbpsMethod
#endif
//selects correct feature for RGB/RGBW
#ifdef RGBW
#define PIXELFEATURE NeoGrbwFeature
#else
#define PIXELFEATURE NeoGrbFeature
#endif
//pixelmethod now in NpbWrapper.h
/*
WS2812FX.h - Library for WS2812 LED effects.
@@ -50,14 +29,14 @@
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Modified to work with WLED - differs from Github WS2812FX
Heavily modified to work with WLED - differs from Github WS2812FX
*/
#ifndef WS2812FX_h
#define WS2812FX_h
#include "Arduino.h"
#include <NeoPixelBrightnessBus.h>
#include "NpbWrapper.h"
#define DEFAULT_BRIGHTNESS 50
#define DEFAULT_MODE 0
@@ -78,8 +57,8 @@
#define FX_MODE_COLOR_WIPE 3
#define FX_MODE_COLOR_WIPE_RANDOM 4
#define FX_MODE_RANDOM_COLOR 5
#define FX_MODE_SINGLE_DYNAMIC 6
#define FX_MODE_MULTI_DYNAMIC 7
#define FX_MODE_EASTER 6
#define FX_MODE_DYNAMIC 7
#define FX_MODE_RAINBOW 8
#define FX_MODE_RAINBOW_CYCLE 9
#define FX_MODE_SCAN 10
@@ -99,7 +78,7 @@
#define FX_MODE_STROBE_RAINBOW 24
#define FX_MODE_MULTI_STROBE 25
#define FX_MODE_BLINK_RAINBOW 26
#define FX_MODE_CHASE_WHITE 27
#define FX_MODE_ANDROID 27
#define FX_MODE_CHASE_COLOR 28
#define FX_MODE_CHASE_RANDOM 29
#define FX_MODE_CHASE_RAINBOW 30
@@ -118,8 +97,8 @@
#define FX_MODE_FIREWORKS_RANDOM 43
#define FX_MODE_MERRY_CHRISTMAS 44
#define FX_MODE_FIRE_FLICKER 45
#define FX_MODE_FIRE_FLICKER_SOFT 46
#define FX_MODE_FADE_DOWN 47
#define FX_MODE_GRADIENT 46
#define FX_MODE_LOADING 47
#define FX_MODE_DUAL_COLOR_WIPE_IN_OUT 48
#define FX_MODE_DUAL_COLOR_WIPE_IN_IN 49
#define FX_MODE_DUAL_COLOR_WIPE_OUT_OUT 50
@@ -132,10 +111,10 @@
#define FX_MODE_CC_RANDOM 57
class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
class WS2812FX {
typedef void (WS2812FX::*mode_ptr)(void);
public:
WS2812FX(uint16_t n) : NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD>(n,PIN) {
WS2812FX(){
_mode[FX_MODE_STATIC] = &WS2812FX::mode_static;
_mode[FX_MODE_BLINK] = &WS2812FX::mode_blink;
@@ -143,8 +122,8 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
_mode[FX_MODE_COLOR_WIPE] = &WS2812FX::mode_color_wipe;
_mode[FX_MODE_COLOR_WIPE_RANDOM] = &WS2812FX::mode_color_wipe_random;
_mode[FX_MODE_RANDOM_COLOR] = &WS2812FX::mode_random_color;
_mode[FX_MODE_SINGLE_DYNAMIC] = &WS2812FX::mode_single_dynamic;
_mode[FX_MODE_MULTI_DYNAMIC] = &WS2812FX::mode_multi_dynamic;
_mode[FX_MODE_EASTER] = &WS2812FX::mode_easter;
_mode[FX_MODE_DYNAMIC] = &WS2812FX::mode_dynamic;
_mode[FX_MODE_RAINBOW] = &WS2812FX::mode_rainbow;
_mode[FX_MODE_RAINBOW_CYCLE] = &WS2812FX::mode_rainbow_cycle;
_mode[FX_MODE_SCAN] = &WS2812FX::mode_scan;
@@ -164,7 +143,7 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
_mode[FX_MODE_STROBE_RAINBOW] = &WS2812FX::mode_strobe_rainbow;
_mode[FX_MODE_MULTI_STROBE] = &WS2812FX::mode_multi_strobe;
_mode[FX_MODE_BLINK_RAINBOW] = &WS2812FX::mode_blink_rainbow;
_mode[FX_MODE_CHASE_WHITE] = &WS2812FX::mode_chase_white;
_mode[FX_MODE_ANDROID] = &WS2812FX::mode_android;
_mode[FX_MODE_CHASE_COLOR] = &WS2812FX::mode_chase_color;
_mode[FX_MODE_CHASE_RANDOM] = &WS2812FX::mode_chase_random;
_mode[FX_MODE_CHASE_RAINBOW] = &WS2812FX::mode_chase_rainbow;
@@ -183,8 +162,8 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
_mode[FX_MODE_FIREWORKS_RANDOM] = &WS2812FX::mode_fireworks_random;
_mode[FX_MODE_MERRY_CHRISTMAS] = &WS2812FX::mode_merry_christmas;
_mode[FX_MODE_FIRE_FLICKER] = &WS2812FX::mode_fire_flicker;
_mode[FX_MODE_FIRE_FLICKER_SOFT] = &WS2812FX::mode_fire_flicker_soft;
_mode[FX_MODE_FADE_DOWN] = &WS2812FX::mode_fade_down;
_mode[FX_MODE_GRADIENT] = &WS2812FX::mode_gradient;
_mode[FX_MODE_LOADING] = &WS2812FX::mode_loading;
_mode[FX_MODE_DUAL_COLOR_WIPE_IN_OUT] = &WS2812FX::mode_dual_color_wipe_in_out;
_mode[FX_MODE_DUAL_COLOR_WIPE_IN_IN] = &WS2812FX::mode_dual_color_wipe_in_in;
_mode[FX_MODE_DUAL_COLOR_WIPE_OUT_OUT] = &WS2812FX::mode_dual_color_wipe_out_out;
@@ -200,18 +179,18 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
_speed = DEFAULT_SPEED;
_brightness = DEFAULT_BRIGHTNESS;
_running = false;
_led_count = n;
_led_count = 255;
_mode_last_call_time = 0;
_mode_delay = 0;
_color = DEFAULT_COLOR;
_mode_color = DEFAULT_COLOR;
_color_sec = 0;
_mode_color_sec = 0;
_mode_var1 = 0;
_cc_fs = true;
_cc_fe = false;
_cc_is = 0;
_cc_i1 = 0;
_cc_i2 = n-1;
_cc_i2 = 254;
_cc_num1 = 5;
_cc_num2 = 5;
_ccStep = 1;
@@ -220,21 +199,24 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
_counter_ccStep = 0;
_fastStandard = false;
_reverseMode = false;
_locked = new bool[n];
_skipFirstMode = false;
_locked = NULL;
_cronixieDigits = new byte[6];
bus = new NeoPixelWrapper();
}
void
show(void),
setPixelColor(uint16_t i, byte r, byte g, byte b),
init(void),
setPixelColor(uint16_t i, byte r, byte g, byte b, byte w),
init(bool supportWhite, uint16_t countPixels, uint8_t pin, bool skipFirst),
service(void),
start(void),
stop(void),
setMode(byte m),
setCustomChase(byte i1, byte i2, byte is, byte np, byte ns, byte stp, bool fs, bool fe),
setCustomChase(byte i1, uint16_t i2, byte is, byte np, byte ns, byte stp, bool fs, bool fe),
setCCIndex1(byte i1),
setCCIndex2(byte i2),
setCCIndex2(uint16_t i2),
setCCStart(byte is),
setCCNum1(byte np),
setCCNum2(byte ns),
@@ -270,7 +252,6 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
unlockAll(void),
setFastUpdateMode(bool b),
trigger(void),
setLedCount(uint16_t i),
setFade(int sp);
bool
@@ -290,16 +271,16 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
getColor(void);
double
getPowerEstimate(byte leds, uint32_t c, byte b),
getSafePowerMultiplier(double safeMilliAmps, byte leds, uint32_t c, byte b);
getPowerEstimate(uint16_t leds, uint32_t c, byte b),
getSafePowerMultiplier(double safeMilliAmps, uint16_t leds, uint32_t c, byte b);
private:
NeoPixelWrapper *bus;
void
begin(void),
begin(bool supportWhite, uint16_t countPixels, uint8_t pin, bool skipFirst),
clear(void),
setPixelColor(uint16_t i, uint32_t c),
setPixelColor(uint16_t i, byte r, byte g, byte b, byte w),
setPixelColorRaw(uint16_t i, byte r, byte g, byte b, byte w),
dofade(void),
strip_off(void),
@@ -309,8 +290,8 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
mode_color_wipe(void),
mode_color_wipe_random(void),
mode_random_color(void),
mode_single_dynamic(void),
mode_multi_dynamic(void),
mode_easter(void),
mode_dynamic(void),
mode_breath(void),
mode_fade(void),
mode_scan(void),
@@ -331,7 +312,7 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
mode_strobe_rainbow(void),
mode_multi_strobe(void),
mode_blink_rainbow(void),
mode_chase_white(void),
mode_android(void),
mode_chase_color(void),
mode_chase_random(void),
mode_chase_rainbow(void),
@@ -339,6 +320,7 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
mode_chase_flash_random(void),
mode_chase_rainbow_white(void),
mode_colorful(void),
mode_colorful_internal(uint32_t*),
mode_traffic_light(void),
mode_color_sweep_random(void),
mode_running_color(void),
@@ -350,9 +332,8 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
mode_fireworks_random(void),
mode_merry_christmas(void),
mode_fire_flicker(void),
mode_fire_flicker_soft(void),
mode_fire_flicker_int(int),
mode_fade_down(void),
mode_gradient(void),
mode_loading(void),
mode_dual_color_wipe_in_out(void),
mode_dual_color_wipe_in_in(void),
mode_dual_color_wipe_out_out(void),
@@ -367,6 +348,8 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
bool
_triggered,
_rgbwMode,
_skipFirstMode,
_fastStandard,
_reverseMode,
_cronixieMode,
@@ -379,13 +362,10 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
_locked;
byte
minval(byte v, byte w),
maxval(byte v, byte w),
_mode_index,
_speed,
_intensity,
_cc_i1,
_cc_i2,
_cc_is,
_cc_num1,
_cc_num2,
@@ -396,6 +376,9 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
_cronixieDigits;
uint16_t
minval(uint16_t v, uint16_t w),
maxval(uint16_t v, uint16_t w),
_cc_i2,
_led_count;
uint32_t
@@ -405,8 +388,8 @@ class WS2812FX : public NeoPixelBrightnessBus<PIXELFEATURE, PIXELMETHOD> {
_counter_mode_call,
_counter_mode_step,
_counter_ccStep,
_mode_var1,
_mode_color,
_mode_color_sec,
_mode_delay;
double

View File

@@ -1,8 +1,8 @@
<!DOCTYPE html>
<html>
<head><meta charset="utf-8">
<head><meta charset="utf-8"><meta name="theme-color" content="#fff">
<link rel='shortcut icon' type='image/x-icon' href='/favicon.ico'/>
<title>WLED 0.5.0</title>
<title>WLED 0.7.1</title>
<script>
var d=document;
var w=window.getComputedStyle(d.querySelector("html"));
@@ -33,6 +33,7 @@
aC = w.getPropertyValue("--aCol");
bC = w.getPropertyValue("--bCol");
dC = w.getPropertyValue("--dCol");
d.querySelector("meta[name=theme-color]").setAttribute("content",bC);
CV(0);
setInterval('GIO()', 5000);
GIO();
@@ -75,7 +76,7 @@
}
}
}
request.open("GET", "win/" +resp +nocache, true);
request.open("GET", "win" +resp +nocache, true);
request.send(null);
resp="";
}
@@ -197,6 +198,7 @@
function SwFX(s)
{
var n=Cf.TX.selectedIndex+s;
if (n==-1||n==58) return;
Cf.TX.selectedIndex =n;
if (n < 0) Cf.TX.selectedIndex = 0;
if (n > 57) Cf.TX.selectedIndex = 53;
@@ -214,24 +216,25 @@
function SwitchPS(x)
{
d.Cf.FF.value = parseInt(d.Cf.FF.value) +x;
if (d.Cf.FF.value < 0) d.Cf.FF.value = 0;
if (d.Cf.FF.value > 24) d.Cf.FF.value = 24;
if (d.Cf.FF.value < 1) d.Cf.FF.value = 1;
if (d.Cf.FF.value > 25) d.Cf.FF.value = 25;
}
function PAt()
{
resp+=(d.Cf.BC.checked)?"&PA=1":"&PA=0";
resp+=(d.Cf.CC.checked)?"&PC=1":"&PC=0";
resp+=(d.Cf.FC.checked)?"&PX=1":"&PX=0";
}
function PSIO(sv)
{
PAt();
if(sv)
{
resp+="&PS=";
resp+=d.Cf.FF.value;
} else
{
if (d.Cf.BC.checked&&d.Cf.CC.checked&&d.Cf.FC.checked)
{resp+="&PL=";resp+=d.Cf.FF.value;}
else {
if(d.Cf.BC.checked){resp+="&PA=";resp+=d.Cf.FF.value;}
if(d.Cf.CC.checked){resp+="&PC=";resp+=d.Cf.FF.value;}
if(d.Cf.FC.checked){resp+="&PX=";resp+=d.Cf.FF.value;}
}
resp+="&PL=";resp+=d.Cf.FF.value;
}
GIO();
}
@@ -335,14 +338,28 @@
}
GIO();
}
function uCY()
{
PAt();
resp+=(d.Cf.CY.checked)?"&CY=1":"&CY=0";
resp+="&P1=" + Cf.P1.value;
resp+="&P2=" + Cf.P2.value;
resp+="&PT=" + Cf.PT.value;
GIO();
}
function R()
{
resp+="&PL=0";GIO();
}
</script>
<style>
:root {
--aCol: #0ac;
--bCol: #124;
--cCol: #334;
--dCol: #288;
--sCol: #FF00FF;
--aCol: #D9B310;
--bCol: #0B3C5D;
--cCol: #1D2731;
--dCol: #328CC1;
--sCol: #000;
--tCol: #328CC1;
--cFn: Verdana;
}
.ctrl_box {
@@ -575,14 +592,14 @@
<svg id="fmf" onclick="SwFX(1)"><use xlink:href="#lnr-arrow-right-circle"></use></svg>
<svg id="fof" onclick="SwFX(99)"><use xlink:href="#lnr-rocket"></use></svg><br><br>
<select name="TX" onchange="GX()">
<option value="0" selected>Static (0)</option>
<option value="0" selected>Solid (0)</option>
<option value="1">Blink (1)</option>
<option value="2">Breath (2)</option>
<option value="3">Wipe (3)</option>
<option value="4">Wipe Random (4)</option>
<option value="5">Color R (5)</option>
<option value="6">Single Dynamic (6)</option>
<option value="7">All Dynamic (7)</option>
<option value="6">Easter (6)</option>
<option value="7">Dynamic (7)</option>
<option value="8">Colorloop (8)</option>
<option value="9">Rainbow (9)</option>
<option value="10">Scan (10)</option>
@@ -602,8 +619,8 @@
<option value="24">Strobe Cl (24)</option>
<option value="25">Strobe + (25)</option>
<option value="26">Blink Cl (26)</option>
<option value="27">Chase (27)</option>
<option value="28">Chase Inv (28)</option>
<option value="27">Android (27)</option>
<option value="28">Chase (28)</option>
<option value="29">Chase R (29)</option>
<option value="30">Chase Rainbow (30)</option>
<option value="31">Chase Flash (31)</option>
@@ -621,8 +638,8 @@
<option value="43">Fireworks R (43)</option>
<option value="44">Christmas (44)</option>
<option value="45">Fire Flicker (45)</option>
<option value="46">Unused (46)</option>
<option value="47">Internal (47)</option>
<option value="46">Gradient (46)</option>
<option value="47">Loading (47)</option>
<option value="48">Wipe IO (48)</option>
<option value="49">Wipe II (49)</option>
<option value="50">Wipe OO (50)</option>
@@ -659,9 +676,10 @@
<svg id="psp" onclick="SwitchPS(-1)"><use xlink:href="#lnr-arrow-left-circle"></use></svg>
<svg id="psn" onclick="SwitchPS(1)"><use xlink:href="#lnr-arrow-right-circle"></use></svg>
<svg id="pss" onclick="PSIO(true)"><use xlink:href="#lnr-arrow-down-circle"></use></svg>
<br><input id="psI" name = "FF" type="number" value="0" min="0" max="25" step="1"><br><br>
Click checkmark to apply <input type="checkbox" checked="true" name="BC"> brightness, <input type="checkbox" checked="true" name="CC"> color and <input type="checkbox" checked="true" name="FC"> effects.<br>
Effect 0 is the configuration when the light is powered up.
<br><input id="psI" name = "FF" type="number" value="1" min="1" max="25" step="1"><br><br>
Click checkmark to apply <input type="checkbox" checked="true" name="BC"> brightness, <input type="checkbox" checked="true" name="CC"> color and <input type="checkbox" checked="true" name="FC"> effects.<br><br>
Cycle through presets <input id="cy1" name="P1" type="number" value="1" min="1" max="25" step="1"> to <input id="cy2" name="P2" type="number" value="5" min="1" max="25" step="1">, keep each for <input id="cyT" name="PT" type="number" value="1250" min="50" max="65501" step="1">ms: <input type="checkbox" name="CY" onclick="uCY()"><br><br>
<button type="button" onclick="R()">Apply boot config</button><br>
</div>
<div id="tlN" class="tools">
Timed Light<br><br>

File diff suppressed because one or more lines are too long

View File

@@ -9,7 +9,7 @@
window.location = "/settings";
}
function RP() {
top.location.href=top.location.href;
top.location.href="/";
}
</script>
<style>

View File

@@ -19,6 +19,9 @@
margin: 0;
background-attachment: fixed;
}
html {
--h:11.55vh;
}
button {
background: var(--bCol);
color: var(--tCol);
@@ -27,13 +30,23 @@
display: inline-block;
filter: drop-shadow( -5px -5px 5px var(--sCol) );
font-size: 8vmin;
height:13.86vh;
height:var(--h);
width: 95%;
margin-top: 2.4vh;
}
</style>
<script>
function BB()
{
if (window.frameElement) {
document.getElementById("b").style.display = "none";
document.documentElement.style.setProperty('--h',"13.86vh");
}
}
</script>
</head>
<body>
<body onload="BB()">
<form action="/"><button type=submit id="b">Back</button></form>
<form action="/settings/wifi"><button type="submit">WiFi Setup</button></form>
<form action="/settings/leds"><button type="submit">LED Preferences</button></form>
<form action="/settings/ui"><button type="submit">User Interface</button></form>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -7,15 +7,15 @@ body{font-family:var(--cFn),sans-serif;text-align:center;background:var(--cCol);
const char PAGE_settings0[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<head>
<title>WLED Settings</title>
<html><head><title>WLED Settings</title>
)=====";
const char PAGE_settings1[] PROGMEM = R"=====(
body{text-align:center;background:var(--cCol);height:100%;margin:0;background-attachment:fixed}button{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:8vmin;height:13.86vh;width:95%;margin-top:2.4vh}</style>
body{text-align:center;background:var(--cCol);height:100%;margin:0;background-attachment:fixed}html{--h:11.55vh}button{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),Helvetica,sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:8vmin;height:var(--h);width:95%;margin-top:2.4vh}</style>
<script>function BB(){if(window.frameElement){document.getElementById("b").style.display="none";document.documentElement.style.setProperty("--h","13.86vh")}};</script>
</head>
<body>
<body onload=BB()>
<form action=/><button type=submit id=b>Back</button></form>
<form action=/settings/wifi><button type=submit>WiFi Setup</button></form>
<form action=/settings/leds><button type=submit>LED Preferences</button></form>
<form action=/settings/ui><button type=submit>User Interface</button></form>
@@ -28,8 +28,7 @@ body{text-align:center;background:var(--cCol);height:100%;margin:0;background-at
const char PAGE_settings_wifi0[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<head>
<html><head>
<title>WiFi Settings</title><script>function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#wifi-settings");}function B(){window.history.back();}function GetV(){var d = document;
)=====";
const char PAGE_settings_wifi1[] PROGMEM = R"=====(
@@ -85,24 +84,26 @@ const char PAGE_settings_leds1[] PROGMEM = R"=====(
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<h2>LED setup</h2>
LED count (max. 255): <input name="LC" type="number" min="1" max="255" required><br>
<i>The default boot color is always saved in preset slot 0.</i><br>
Alternatively, apply preset <input name="BP" type="number" min="0" max="25" required> at boot<br>
LED count: <input name="LC" type="number" min="1" max="1200" required><br>
LEDs are 4-channel type (RGBW): <input type="checkbox" name="EW"><br>
Apply preset <input name="BP" type="number" min="0" max="25" required> at boot (0 uses defaults)<br>
Default RGB color:
<input name="CR" type="number" min="0" max="255" required>
<input name="CG" type="number" min="0" max="255" required>
<input name="CB" type="number" min="0" max="255" required><br>
Default white value (only RGBW): <input name="CW" type="number" min="0" max="255" required><br>
Auto-calculate white from RGB instead: <input type="checkbox" name="AW"><br>
Default brightness: <input name="CA" type="number" min="0" max="255" required> (0-255)<br>
Default white value (only RGBW, -1 to disable): <input name="CW" type="number" min="-1" max="255" required><br>
Default effect ID: <input name="FX" type="number" min="0" max="57" required> <br>
Default effect speed: <input name="SX" type="number" min="0" max="255" required> <br>
Default effect intensity: <input name="IX" type="number" min="0" max="255" required> <br>
Default effect ID: <input name="FX" type="number" min="0" max="57" required><br>
Default effect speed: <input name="SX" type="number" min="0" max="255" required><br>
Default effect intensity: <input name="IX" type="number" min="0" max="255" required><br>
Default secondary RGB(W):<br>
<input name="SR" type="number" min="0" max="255" required>
<input name="SG" type="number" min="0" max="255" required>
<input name="SB" type="number" min="0" max="255" required>
<input name="SW" type="number" min="0" max="255" required><br>
Ignore and use current color, brightness and effects: <input type="checkbox" name="IS"><br>
Save current preset cycle configuration as boot default: <input type="checkbox" name="PC"><br>
Turn on after power up/reset: <input type="checkbox" name="BO"><br>
Use Gamma correction for brightness: <input type="checkbox" name="GB"><br>
Use Gamma correction for color: <input type="checkbox" name="GC"><br>
@@ -110,7 +111,8 @@ Brightness factor: <input name="BF" type="number" min="0" max="255" required> %
<h3>Transitions</h3>
Fade: <input type="checkbox" name="TF"><br>
Sweep: <input type="checkbox" name="TS"> Invert direction: <input type="checkbox" name="TI"><br>
Transition Delay: <input name="TD" maxlength="5" size="2"> ms
Transition Time: <input name="TD" maxlength="5" size="2"> ms<br>
Enable transition for secondary color: <input type="checkbox" name="T2"><br>
<h3>Timed light</h3>
Default Duration: <input name="TL" type="number" min="1" max="255" required> min<br>
Default Target brightness: <input name="TB" type="number" min="0" max="255" required><br>
@@ -118,7 +120,7 @@ Fade down: <input type="checkbox" name="TW"><br>
<h3>Advanced</h3>
Reverse LED order (rotate 180): <input type="checkbox" name="RV"><br>
Init LEDs after WiFi: <input type="checkbox" name="EI"><br>
WARLS offset: <input name="WO" type="number" min="-255" max="255" required><hr>
Skip first LED: <input type="checkbox" name="SL"><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
</form>
</body>
@@ -127,8 +129,7 @@ WARLS offset: <input name="WO" type="number" min="-255" max="255" required><hr>
const char PAGE_settings_ui0[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<head>
<html><head>
<title>UI Settings</title><script>
function gId(s){return document.getElementById(s);}function S(){GetV();Ct();}function H(){window.open("https://github.com/Aircoookie/WLED/wiki/Settings#user-interface-settings");}function B(){window.history.back();}function Ct(){if (gId("co").selected){gId("cth").style.display="block";}else{gId("cth").style.display="none";}}function GetV(){var d = document;
)=====";
@@ -139,7 +140,14 @@ const char PAGE_settings_ui1[] PROGMEM = R"=====(
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button><hr>
<h2>Web Setup</h2>
Server description: <input name="DS" maxlength="32"><br>
User Interface Mode:
<select name="UI">
<option value="0" selected>Auto</option>
<option value="1">Classic</option>
<option value="2">Mobile</option>
</select><br>
Server description: <input name="DS" maxlength="32"><br><br>
<i>The following options are for the classic UI!</i><br>
Use HSB sliders instead of RGB by default: <input type="checkbox" name="MD"><br>
Color Theme:
<select name="TH" onchange="Ct()">
@@ -155,7 +163,7 @@ Color Theme:
<option value="9">Nixie</option>
<option value="10">Terminal</option>
<option value="11">C64</option>
<option value="12">Placeholder</option>
<option value="12">Easter</option>
<option value="13">Placeholder</option>
<option value="14">The End</option>
<option value="15" id="co">Custom</option>
@@ -197,12 +205,28 @@ Send notifications on direct change: <input type="checkbox" name="SD"><br>
Send notifications on button press: <input type="checkbox" name="SB"><br>
Send Alexa notifications: <input type="checkbox" name="SA"><br>
Send Philips Hue change notifications: <input type="checkbox" name="SH"><br>
Send notifications twice: <input type="checkbox" name="S2">
Send notifications twice: <input type="checkbox" name="S2"><br>
<h3>Realtime</h3>
Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
<i>E1.31 (sACN)</i><br>
Use E1.31 multicast: <input type="checkbox" name="EM"><br>
E1.31 universe: <input name="EU" type="number" min="1" max="63999" required><br>
<i>Reboot required.</i> Check out <a href="https://github.com/ahodges9/LedFx" target="_blank">LedFx</a>!<br><br>
Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
Force max brightness: <input type="checkbox" name="FB"><br>
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required><br>
Enable UI access during realtime: <input type="checkbox" name="RU"> (can cause issues)
<h3>Alexa Voice Assistant</h3>
Emulate Alexa device: <input type="checkbox" name="AL"><br>
Alexa invocation name: <input name="AI" maxlength="32"><br>
Alexa invocation name: <input name="AI" maxlength="32">
<h3>Blynk</h3>
Device Auth token: <input name="BK" maxlength="33"><br>
<i>Clear the token field to disable. </i><a href="https://github.com/Aircoookie/WLED/wiki/Blynk" target="_blank">Setup info</a>
<h3>Philips Hue</h3>
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
Poll Hue light <input name="HL" type="number" min="1" max="99" required> every <input name="HI" type="number" min="100" max="65000" required> ms: <input type="checkbox" name="HP"><br>
Then, receive <input type="checkbox" name="HO"> On/Off, <input type="checkbox" name="HB"> Brightness, and <input type="checkbox" name="HC"> Color<br>
Hue Bridge IP:<br>
<input name="H0" type="number" min="0" max="255" required> .
<input name="H1" type="number" min="0" max="255" required> .
@@ -210,8 +234,6 @@ Hue Bridge IP:<br>
<input name="H3" type="number" min="0" max="255" required><br>
<b>Press the pushlink button on the bridge, after that save this page!</b><br>
(when first connecting)<br>
Poll Hue light <input name="HL" type="number" min="1" max="99" required> every <input name="HI" type="number" min="100" max="65000" required> ms: <input type="checkbox" name="HP"><br>
Then, receive <input type="checkbox" name="HO"> On/Off, <input type="checkbox" name="HB"> Brightness, and <input type="checkbox" name="HC"> Color<br>
Hue status: <span class="hms"> Internal ESP Error! </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save</button>
</form>
@@ -248,6 +270,7 @@ Time zone:
<option value="10">JST(KST)</option>
<option value="11">AEST/AEDT</option>
<option value="12">NZST/NZDT</option>
<option value="13">North Korea</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>.
@@ -318,7 +341,7 @@ const char PAGE_settings_sec1[] PROGMEM = R"=====(
<div class="helpB"><button type="button" onclick="H()">?</button></div>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button><hr>
<h2>Security & Update setup</h2>
Enable OTA lock: <input type="checkbox" name="NO"><br>
Lock wireless (OTA) software update: <input type="checkbox" name="NO"><br>
Passphrase: <input type="password" name="OP" maxlength="32"><br>
To enable OTA, for security reasons you need to also enter the correct password!<br>
The password should be changed when OTA is enabled.<br>
@@ -335,16 +358,21 @@ 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">WLED</a> version 0.6.0<br>
<a href="https://github.com/Aircoookie/WLED" target="_blank">WLED</a> version 0.7.1<br><br>
<b>Contributors:</b><br>
StormPie <i>(Mobile HTML UI)</i><br><br>
Thank you so much!<br><br>
(c) 2016-2018 Christian Schwinne <br>
<i>Licensed under the MIT license</i><br><br>
<i>Uses libraries:</i><br>
<b>Uses libraries:</b><br>
<i>ESP8266/ESP32 Arduino Core</i><br>
<i>(ESP32) <a href="https://github.com/bbx10/WebServer_tng">WebServer_tng</a> by bbx10</i><br>
<i><a href="https://github.com/kitesurfer1404/WS2812FX">WS2812FX</a> by kitesurfer1404 (modified)</i><br>
<i><a href="https://github.com/JChristensen/Timezone">Timezone</a> library by JChristensen</i><br>
<i><a href="https://github.com/Aircoookie/Espalexa">Espalexa</a> by Aircoookie (modified)</i><br><br>
<i>UI icons by <a href="https://linearicons.com">Linearicons</a> created by <a href="https://perxis.com">Perxis</a>! (CC-BY-SA 4.0)</i> <br><br>
<i>(ESP32) <a href="https://github.com/bbx10/WebServer_tng" target="_blank">WebServer_tng</a> by bbx10</i><br>
<i><a href="https://github.com/kitesurfer1404/WS2812FX" target="_blank">WS2812FX</a> by kitesurfer1404 (modified)</i><br>
<i><a href="https://github.com/JChristensen/Timezone" target="_blank">Timezone</a> library by JChristensen</i><br>
<i><a href="https://github.com/blynkkk/blynk-library" target="_blank">Blynk</a> library (compacted)</i><br>
<i><a href="https://github.com/forkineye/E131" target="_blank">E1.31</a> library by forkineye (modified)</i><br>
<i><a href="https://github.com/Aircoookie/Espalexa" target="_blank">Espalexa</a> by Aircoookie (modified)</i><br><br>
<i>UI icons by <a href="https://linearicons.com" target="_blank">Linearicons</a> created by <a href="https://perxis.com" target="_blank">Perxis</a>! (CC-BY-SA 4.0)</i> <br><br>
Server message: <span class="msg"> Response error! </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
</form>

View File

@@ -1,3 +1,7 @@
//USER HTML
const char PAGE_usermod[] PROGMEM = R"=====(
<html><body>There is no usermod installed or it doesn't specify a custom web page.</body></html>
)=====";
/*
* Various
*/
@@ -5,7 +9,7 @@ const char PAGE_msg0[] PROGMEM = R"=====(
<!DOCTYPE html>
<html><head>
<title>WLED Message</title>
<script>function B(){window.history.back()};function RS(){window.location = "/settings";}function RP(){top.location.href=top.location.href;}</script>
<script>function B(){window.history.back()};function RS(){window.location = "/settings";}function RP(){top.location.href="/";}</script>
)=====";
const char PAGE_msg1[] PROGMEM = R"=====(
button{background:var(--bCol);color:var(--tCol);font-family:var(--cFn),sans-serif;border:.3ch solid var(--bCol);display:inline-block;filter:drop-shadow(-5px -5px 5px var(--sCol));font-size:20px;margin:8px;margin-top:12px}body{font-family:var(--cFn),sans-serif;text-align:center;background:var(--cCol);color:var(--tCol);line-height:200%;margin:0;background-attachment:fixed}</style>

View File

@@ -0,0 +1,321 @@
/**
* @file BlynkApi.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Jan 2015
* @brief High-level functions
*
*/
#ifndef BlynkApi_h
#define BlynkApi_h
#include "BlynkConfig.h"
#include "BlynkDebug.h"
#include "BlynkParam.h"
#include "BlynkTimer.h"
#include "BlynkHandlers.h"
#include "BlynkProtocolDefs.h"
#if defined(BLYNK_EXPERIMENTAL)
#include <Blynk/BlynkEveryN.h>
#endif
/**
* Represents high-level functions of Blynk
*/
template <class Proto>
class BlynkApi
{
public:
BlynkApi() {
}
#ifdef DOXYGEN // These API here are only for the documentation
/**
* Connects to the server.
* Blocks until connected or timeout happens.
* May take less or more then timeout value.
*
* @param timeout Connection timeout
* @returns True if connected to the server
*/
bool connect(unsigned long timeout = BLYNK_TIMEOUT_MS*3);
/**
* Disconnects from the server.
* It will not try to reconnect, until connect() is called
*/
void disconnect();
/**
* @returns True if connected to the server
*/
bool connected();
/**
* Performs Blynk-related housekeeping
* and processes incoming commands
*
* @param available True if there is incoming data to process
* Only used when user manages connection manually.
*/
bool run(bool available = false);
#endif // DOXYGEN
/**
* Sends value to a Virtual Pin
*
* @param pin Virtual Pin number
* @param data Value to be sent
*/
template <typename... Args>
void virtualWrite(int pin, Args... values) {
char mem[BLYNK_MAX_SENDBYTES];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add("vw");
cmd.add(pin);
cmd.add_multi(values...);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, cmd.getBuffer(), cmd.getLength()-1);
}
/**
* Sends buffer to a Virtual Pin
*
* @param pin Virtual Pin number
* @param buff Data buffer
* @param len Length of data
*/
void virtualWriteBinary(int pin, const void* buff, size_t len) {
char mem[8];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add("vw");
cmd.add(pin);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, cmd.getBuffer(), cmd.getLength(), buff, len);
}
/**
* Sends BlynkParam to a Virtual Pin
*
* @param pin Virtual Pin number
* @param param
*/
void virtualWrite(int pin, const BlynkParam& param) {
virtualWriteBinary(pin, param.getBuffer(), param.getLength());
}
void virtualWrite(int pin, const BlynkParamAllocated& param) {
virtualWriteBinary(pin, param.getBuffer(), param.getLength());
}
/**
* Requests Server to re-send current values for all widgets.
*/
void syncAll() {
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE_SYNC);
}
/**
* Sends internal command
*/
template <typename... Args>
void sendInternal(Args... params) {
char mem[BLYNK_MAX_SENDBYTES];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add_multi(params...);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_INTERNAL, 0, cmd.getBuffer(), cmd.getLength()-1);
}
/**
* Requests App or Server to re-send current value of a Virtual Pin.
* This will probably cause user-defined BLYNK_WRITE handler to be called.
*
* @param pin Virtual Pin number
*/
template <typename... Args>
void syncVirtual(Args... pins) {
char mem[BLYNK_MAX_SENDBYTES];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add("vr");
cmd.add_multi(pins...);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE_SYNC, 0, cmd.getBuffer(), cmd.getLength()-1);
}
/**
* Tweets a message
*
* @param msg Text of the message
*/
template<typename T>
void tweet(const T& msg) {
char mem[BLYNK_MAX_SENDBYTES];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add(msg);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_TWEET, 0, cmd.getBuffer(), cmd.getLength()-1);
}
/**
* Sends a push notification to the App
*
* @param msg Text of the message
*/
template<typename T>
void notify(const T& msg) {
char mem[BLYNK_MAX_SENDBYTES];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add(msg);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_NOTIFY, 0, cmd.getBuffer(), cmd.getLength()-1);
}
/**
* Sends an SMS
*
* @param msg Text of the message
*/
template<typename T>
void sms(const T& msg) {
char mem[BLYNK_MAX_SENDBYTES];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add(msg);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_SMS, 0, cmd.getBuffer(), cmd.getLength()-1);
}
/**
* Sends an email message
*
* @param email Email to send to
* @param subject Subject of message
* @param msg Text of the message
*/
template <typename T1, typename T2>
void email(const char* email, const T1& subject, const T2& msg) {
char mem[BLYNK_MAX_SENDBYTES];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add(email);
cmd.add(subject);
cmd.add(msg);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_EMAIL, 0, cmd.getBuffer(), cmd.getLength()-1);
}
/**
* Sends an email message
*
* @param subject Subject of message
* @param msg Text of the message
*/
template <typename T1, typename T2>
void email(const T1& subject, const T2& msg) {
char mem[BLYNK_MAX_SENDBYTES];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add(subject);
cmd.add(msg);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_EMAIL, 0, cmd.getBuffer(), cmd.getLength()-1);
}
/**
* Sets property of a Widget
*
* @experimental
*
* @param pin Virtual Pin number
* @param property Property name ("label", "labels", "color", ...)
* @param value Property value
*/
template <typename T, typename... Args>
void setProperty(int pin, const T& property, Args... values) {
char mem[BLYNK_MAX_SENDBYTES];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add(pin);
cmd.add(property);
cmd.add_multi(values...);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_PROPERTY, 0, cmd.getBuffer(), cmd.getLength()-1);
}
template <typename T>
void setProperty(int pin, const T& property, const BlynkParam& param) {
char mem[32];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add(pin);
cmd.add(property);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_PROPERTY, 0, cmd.getBuffer(), cmd.getLength(), param.getBuffer(), param.getLength());
}
template <typename T>
void setProperty(int pin, const T& property, const BlynkParamAllocated& param) {
char mem[32];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add(pin);
cmd.add(property);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_PROPERTY, 0, cmd.getBuffer(), cmd.getLength(), param.getBuffer(), param.getLength());
}
template <typename NAME>
void logEvent(const NAME& event_name) {
char mem[BLYNK_MAX_SENDBYTES];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add(event_name);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_EVENT_LOG, 0, cmd.getBuffer(), cmd.getLength());
}
template <typename NAME, typename DESCR>
void logEvent(const NAME& event_name, const DESCR& description) {
char mem[BLYNK_MAX_SENDBYTES];
BlynkParam cmd(mem, 0, sizeof(mem));
cmd.add(event_name);
cmd.add(description);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_EVENT_LOG, 0, cmd.getBuffer(), cmd.getLength());
}
#if defined(BLYNK_EXPERIMENTAL)
// Attention!
// Every function in this section may be changed, removed or renamed.
/**
* Refreshes value of a widget by running
* user-defined BLYNK_READ handler of a pin.
*
* @experimental
*
* @param pin Virtual Pin number
*/
void refresh(int pin) {
if (WidgetReadHandler handler = GetReadHandler(pin)) {
BlynkReq req = { 0, BLYNK_SUCCESS, (uint8_t)pin };
handler(req);
}
}
/**
* Delays for N milliseconds, handling server communication in background.
*
* @experimental
* @warning Should be used very carefully, especially on platforms with small RAM.
*
* @param ms Milliseconds to wait
*/
void delay(unsigned long ms) {
uint16_t start = (uint16_t)micros();
while (ms > 0) {
static_cast<Proto*>(this)->run();
#if !defined(BLYNK_NO_YIELD)
yield();
#endif
if (((uint16_t)micros() - start) >= 1000) {
ms--;
start += 1000;
}
}
}
#endif
protected:
void processCmd(const void* buff, size_t len);
void sendInfo();
};
#endif

View File

@@ -0,0 +1,199 @@
/**
* @file BlynkApiArduino.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Mar 2015
* @brief
*
*/
#ifndef BlynkApiArduino_h
#define BlynkApiArduino_h
#include "BlynkApi.h"
#include <Arduino.h>
#ifdef BLYNK_NO_INFO
template<class Proto>
BLYNK_FORCE_INLINE
void BlynkApi<Proto>::sendInfo() {}
#else
template<class Proto>
BLYNK_FORCE_INLINE
void BlynkApi<Proto>::sendInfo()
{
static const char profile[] BLYNK_PROGMEM = "blnkinf\0"
#ifdef BOARD_FIRMWARE_VERSION
BLYNK_PARAM_KV("ver" , BOARD_FIRMWARE_VERSION)
BLYNK_PARAM_KV("blynk" , BLYNK_VERSION)
#else
BLYNK_PARAM_KV("ver" , BLYNK_VERSION)
#endif
#ifdef BOARD_TEMPLATE_ID
BLYNK_PARAM_KV("tmpl" , BOARD_TEMPLATE_ID)
#endif
BLYNK_PARAM_KV("h-beat" , BLYNK_TOSTRING(BLYNK_HEARTBEAT))
BLYNK_PARAM_KV("buff-in", BLYNK_TOSTRING(BLYNK_MAX_READBYTES))
#ifdef BLYNK_INFO_DEVICE
BLYNK_PARAM_KV("dev" , BLYNK_INFO_DEVICE)
#endif
#ifdef BLYNK_INFO_CPU
BLYNK_PARAM_KV("cpu" , BLYNK_INFO_CPU)
#endif
#ifdef BLYNK_INFO_CONNECTION
BLYNK_PARAM_KV("con" , BLYNK_INFO_CONNECTION)
#endif
BLYNK_PARAM_KV("build" , __DATE__ " " __TIME__)
"\0"
;
const size_t profile_len = sizeof(profile)-8-2;
#ifdef BLYNK_HAS_PROGMEM
char mem[profile_len];
memcpy_P(mem, profile+8, profile_len);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_INTERNAL, 0, mem, profile_len);
#else
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_INTERNAL, 0, profile+8, profile_len);
#endif
return;
}
#endif
// Check if analog pins can be referenced by name on this device
#if defined(analogInputToDigitalPin)
#define BLYNK_DECODE_PIN(it) (((it).asStr()[0] == 'A') ? analogInputToDigitalPin(atoi((it).asStr()+1)) : (it).asInt())
#else
#define BLYNK_DECODE_PIN(it) ((it).asInt())
#if defined(BLYNK_DEBUG_ALL)
#pragma message "analogInputToDigitalPin not defined"
#endif
#endif
template<class Proto>
BLYNK_FORCE_INLINE
void BlynkApi<Proto>::processCmd(const void* buff, size_t len)
{
BlynkParam param((void*)buff, len);
BlynkParam::iterator it = param.begin();
if (it >= param.end())
return;
const char* cmd = it.asStr();
uint16_t cmd16;
memcpy(&cmd16, cmd, sizeof(cmd16));
if (++it >= param.end())
return;
uint8_t pin = BLYNK_DECODE_PIN(it);
switch(cmd16) {
#ifndef BLYNK_NO_BUILTIN
case BLYNK_HW_PM: {
while (it < param.end()) {
pin = BLYNK_DECODE_PIN(it);
++it;
if (!strcmp(it.asStr(), "in")) {
pinMode(pin, INPUT);
} else if (!strcmp(it.asStr(), "out") || !strcmp(it.asStr(), "pwm")) {
pinMode(pin, OUTPUT);
#ifdef INPUT_PULLUP
} else if (!strcmp(it.asStr(), "pu")) {
pinMode(pin, INPUT_PULLUP);
#endif
#ifdef INPUT_PULLDOWN
} else if (!strcmp(it.asStr(), "pd")) {
pinMode(pin, INPUT_PULLDOWN);
#endif
} else {
#ifdef BLYNK_DEBUG
BLYNK_LOG4(BLYNK_F("Invalid pin "), pin, BLYNK_F(" mode "), it.asStr());
#endif
}
++it;
}
} break;
case BLYNK_HW_DR: {
char mem[16];
BlynkParam rsp(mem, 0, sizeof(mem));
rsp.add("dw");
rsp.add(pin);
rsp.add(digitalRead(pin));
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, rsp.getBuffer(), rsp.getLength()-1);
} break;
case BLYNK_HW_DW: {
// Should be 1 parameter (value)
if (++it >= param.end())
return;
#ifdef ESP8266
// Disable PWM...
analogWrite(pin, 0);
#endif
#ifndef BLYNK_MINIMIZE_PINMODE_USAGE
pinMode(pin, OUTPUT);
#endif
digitalWrite(pin, it.asInt() ? HIGH : LOW);
} break;
case BLYNK_HW_AR: {
char mem[16];
BlynkParam rsp(mem, 0, sizeof(mem));
rsp.add("aw");
rsp.add(pin);
rsp.add(analogRead(pin));
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_HARDWARE, 0, rsp.getBuffer(), rsp.getLength()-1);
} break;
// TODO: Remove workaround for ESP32
#if !defined(ESP32)
case BLYNK_HW_AW: {
// Should be 1 parameter (value)
if (++it >= param.end())
return;
#ifndef BLYNK_MINIMIZE_PINMODE_USAGE
pinMode(pin, OUTPUT);
#endif
analogWrite(pin, it.asInt());
} break;
#endif // TODO: Remove workaround for ESP32
#endif
case BLYNK_HW_VR: {
BlynkReq req = { pin };
WidgetReadHandler handler = GetReadHandler(pin);
if (handler && (handler != BlynkWidgetRead)) {
handler(req);
} else {
BlynkWidgetReadDefault(req);
}
} break;
case BLYNK_HW_VW: {
++it;
char* start = (char*)it.asStr();
BlynkParam param2(start, len - (start - (char*)buff));
BlynkReq req = { pin };
WidgetWriteHandler handler = GetWriteHandler(pin);
if (handler && (handler != BlynkWidgetWrite)) {
handler(req, param2);
} else {
BlynkWidgetWriteDefault(req, param2);
}
} break;
default:
BLYNK_LOG2(BLYNK_F("Invalid HW cmd: "), cmd);
static_cast<Proto*>(this)->sendCmd(BLYNK_CMD_RESPONSE, static_cast<Proto*>(this)->msgIdOutOverride, NULL, BLYNK_ILLEGAL_COMMAND);
}
}
#endif

View File

@@ -0,0 +1,128 @@
/**
* @file BlynkParam.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Jan 2015
* @brief
*
*/
#ifndef BlynkArduinoClient_h
#define BlynkArduinoClient_h
#include "BlynkApiArduino.h"
#include "BlynkDebug.h"
#include <Client.h>
#if defined(ESP8266) && !defined(BLYNK_NO_YIELD)
#define YIELD_FIX() BLYNK_RUN_YIELD();
#else
#define YIELD_FIX()
#endif
template <typename Client>
class BlynkArduinoClientGen
{
public:
BlynkArduinoClientGen(Client& c)
: client(NULL), domain(NULL), port(0), isConn(false)
{
setClient(&c);
}
BlynkArduinoClientGen()
: client(NULL), domain(NULL), port(0), isConn(false)
{}
void setClient(Client* c) {
client = c;
client->setTimeout(BLYNK_TIMEOUT_MS);
}
void begin(IPAddress a, uint16_t p) {
domain = NULL;
port = p;
addr = a;
}
void begin(const char* d, uint16_t p) {
domain = d;
port = p;
}
bool connect() {
if (domain) {
BLYNK_LOG4(BLYNK_F("Connecting to "), domain, ':', port);
isConn = (1 == client->connect(domain, port));
return isConn;
} else { //if (uint32_t(addr) != 0) {
BLYNK_LOG_IP("Connecting to ", addr);
isConn = (1 == client->connect(addr, port));
return isConn;
}
return false;
}
void disconnect() { isConn = false; client->stop(); }
#ifdef BLYNK_ENC28J60_FIX
size_t read(void* buf, size_t len) {
while (client->available() < len) { BLYNK_RUN_YIELD(); }
return client->read((uint8_t*)buf, len);
}
#else
size_t read(void* buf, size_t len) {
size_t res = client->readBytes((char*)buf, len);
YIELD_FIX();
return res;
}
#endif
#ifdef BLYNK_RETRY_SEND
size_t write(const void* buf, size_t len) {
size_t sent = 0;
int retry = 0;
while (sent < len && ++retry < 10) {
size_t w = client->write((const uint8_t*)buf+sent, len-sent);
if (w != 0 && w != -1) {
sent += w;
} else {
BlynkDelay(50);
#if defined(BLYNK_DEBUG) && defined(BLYNK_PRINT)
BLYNK_PRINT_TIME();
BLYNK_PRINT.print(BLYNK_F("Retry "));
BLYNK_PRINT.print(retry);
BLYNK_PRINT.print(BLYNK_F(" send: "));
BLYNK_PRINT.print(sent);
BLYNK_PRINT.print('/');
BLYNK_PRINT.println(len);
#endif
}
}
return sent;
}
#else
size_t write(const void* buf, size_t len) {
YIELD_FIX();
size_t res = client->write((const uint8_t*)buf, len);
YIELD_FIX();
return res;
}
#endif
bool connected() { YIELD_FIX(); return isConn && client->connected(); }
int available() { YIELD_FIX(); return client->available(); }
protected:
Client* client;
IPAddress addr;
const char* domain;
uint16_t port;
bool isConn;
};
typedef BlynkArduinoClientGen<Client> BlynkArduinoClient;
#endif

View File

@@ -0,0 +1,95 @@
/**
* @file BlynkConfig.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Jan 2015
* @brief Configuration of different aspects of library
*
*/
#ifndef BlynkConfig_h
#define BlynkConfig_h
#include "BlynkDetectDevice.h"
/***************************************************
* Change these settings to match your need
***************************************************/
#define BLYNK_DEFAULT_DOMAIN "blynk-cloud.com"
#define BLYNK_DEFAULT_PORT 80
#define BLYNK_DEFAULT_PORT_SSL 8441
/***************************************************
* Professional settings
***************************************************/
// Library version.
#define BLYNK_VERSION "0.5.3"
// Heartbeat period in seconds.
#ifndef BLYNK_HEARTBEAT
#define BLYNK_HEARTBEAT 10
#endif
// Network timeout in milliseconds.
#ifndef BLYNK_TIMEOUT_MS
#define BLYNK_TIMEOUT_MS 2000UL
#endif
// Limit the amount of outgoing commands per second.
#ifndef BLYNK_MSG_LIMIT
#define BLYNK_MSG_LIMIT 15
#endif
// Limit the incoming command length.
#ifndef BLYNK_MAX_READBYTES
#define BLYNK_MAX_READBYTES 256
#endif
// Limit the outgoing command length.
#ifndef BLYNK_MAX_SENDBYTES
#define BLYNK_MAX_SENDBYTES 128
#endif
// Uncomment to use Let's Encrypt Root CA
//#define BLYNK_SSL_USE_LETSENCRYPT
// Uncomment to disable built-in analog and digital operations.
//#define BLYNK_NO_BUILTIN
// Uncomment to disable providing info about device to the server.
//#define BLYNK_NO_INFO
// Uncomment to enable debug prints.
//#define BLYNK_DEBUG
// Uncomment to force-enable 128 virtual pins
//#define BLYNK_USE_128_VPINS
// Uncomment to disable fancy logo
//#define BLYNK_NO_FANCY_LOGO
// Uncomment to enable 3D fancy logo
//#define BLYNK_FANCY_LOGO_3D
// Uncomment to enable experimental functions.
//#define BLYNK_EXPERIMENTAL
// Uncomment to disable all float/double usage
//#define BLYNK_NO_FLOAT
// Uncomment to switch to direct-connect mode
//#define BLYNK_USE_DIRECT_CONNECT
// Uncomment to append command body to header (uses more RAM)
//#define BLYNK_SEND_ATOMIC
// Split whole command into chunks (in bytes)
//#define BLYNK_SEND_CHUNK 64
// Wait after sending each chunk (in milliseconds)
//#define BLYNK_SEND_THROTTLE 10
#endif

View File

@@ -0,0 +1,173 @@
/**
* @file BlynkDateTime.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date Aug 2016
* @brief DateTime implementation
*
*/
#ifndef BlynkDateTime_h
#define BlynkDateTime_h
typedef long blynk_time_t;
struct blynk_tm *blynk_gmtime_r(const blynk_time_t *time, struct blynk_tm *tm);
blynk_time_t blynk_mk_gmtime(struct blynk_tm *tm);
struct blynk_tm {
int8_t tm_sec;
int8_t tm_min;
int8_t tm_hour;
int8_t tm_mday;
int8_t tm_wday;
int8_t tm_mon;
int16_t tm_year;
int16_t tm_yday;
int16_t tm_isdst;
};
class BlynkTime {
public:
static const uint32_t MAX_TIME = 86400L;
BlynkTime() : mTime(-1) {}
BlynkTime(const BlynkTime& t) : mTime(t.mTime) {}
BlynkTime(long seconds) : mTime(seconds % MAX_TIME) {}
BlynkTime(int hour, int minute, int second)
{
mTime = (hour * 3600 + minute * 60 + second) % MAX_TIME;
}
int second() const { return mTime % 60; }
int minute() const { return (mTime / 60) % 60; }
int hour() const { return mTime / 3600; }
int hour12() const {
int h = hour();
if (h == 0)
return 12; // 12 midnight
else if (h > 12)
return h - 12;
return h;
}
bool isAM() const { return !isPM(); }
bool isPM() const { return (hour() >= 12); }
void adjustSeconds(int sec) {
if (isValid()) {
mTime = (mTime + sec) % MAX_TIME;
}
}
blynk_time_t getUnixOffset() const { return mTime; }
bool isValid() const { return mTime < MAX_TIME; }
operator bool() const { return isValid(); }
bool operator == (const BlynkTime& t) const { return mTime == t.mTime; }
bool operator >= (const BlynkTime& t) const { return mTime >= t.mTime; }
bool operator <= (const BlynkTime& t) const { return mTime <= t.mTime; }
bool operator > (const BlynkTime& t) const { return mTime > t.mTime; }
bool operator < (const BlynkTime& t) const { return mTime < t.mTime; }
private:
uint32_t mTime;
};
class BlynkDateTime {
public:
BlynkDateTime() : mTime(0) {}
BlynkDateTime(const BlynkDateTime& t)
{
mTime = t.mTime;
blynk_gmtime_r(&mTime, &mTm);
}
BlynkDateTime(blynk_time_t t)
{
mTime = t;
blynk_gmtime_r(&mTime, &mTm);
}
BlynkDateTime(int hour, int minute, int second, int day, int month, int year)
{
mTm.tm_hour = hour;
mTm.tm_min = minute;
mTm.tm_sec = second;
mTm.tm_mday = day;
mTm.tm_mon = month - 1;
mTm.tm_year = year - 1900;
mTm.tm_isdst = 0;
mTime = blynk_mk_gmtime(&mTm);
}
int second() const { return mTm.tm_sec; }
int minute() const { return mTm.tm_min; }
int hour() const { return mTm.tm_hour; }
int day() const { return mTm.tm_mday; }
int month() const { return 1 + mTm.tm_mon; }
int year() const { return 1900 + mTm.tm_year; }
int day_of_year() const { return 1 + mTm.tm_yday; }
int day_of_week() const { return mTm.tm_wday == 0 ? 7 : mTm.tm_wday; }
/*int weak_of_year() const {
int julian = day_of_year();
int dow = day_of_week();
int dowJan1 = BlynkDateTime(0,0,0, 1,1,year()).day_of_week();
int weekNum = ((julian + 6) / 7);
if (dow < dowJan1)
++weekNum;
return (weekNum);
}*/
int hour12() const {
int h = hour();
if (h == 0)
return 12; // 12 midnight
else if (h > 12)
return h - 12;
return h;
}
bool isAM() const { return !isPM(); }
bool isPM() const { return (hour() >= 12); }
void adjustSeconds(int sec) {
if (isValid()) {
mTime += sec;
blynk_gmtime_r(&mTime, &mTm);
}
}
//tm& getTm() { return mTm; }
blynk_time_t getUnix() const { return mTime; }
bool isValid() const { return mTime != 0; }
operator bool() const { return isValid(); }
bool operator == (const BlynkDateTime& t) const { return mTime == t.mTime; }
bool operator >= (const BlynkDateTime& t) const { return mTime >= t.mTime; }
bool operator <= (const BlynkDateTime& t) const { return mTime <= t.mTime; }
bool operator > (const BlynkDateTime& t) const { return mTime > t.mTime; }
bool operator < (const BlynkDateTime& t) const { return mTime < t.mTime; }
private:
blynk_tm mTm;
blynk_time_t mTime;
};
#endif

View File

@@ -0,0 +1,278 @@
/**
* @file BlynkDebug.cpp
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Jan 2015
* @brief Debug utilities for Arduino
*/
#include "BlynkDebug.h"
#if defined(ARDUINO) && defined(__AVR__) && defined(BLYNK_USE_AVR_WDT)
#include <Arduino.h>
#include <avr/wdt.h>
BLYNK_CONSTRUCTOR
static void BlynkSystemInit()
{
MCUSR = 0;
wdt_disable();
}
void BlynkReset()
{
wdt_enable(WDTO_15MS);
delay(50);
void(*resetFunc)(void) = 0;
resetFunc();
for(;;) {} // To make compiler happy
}
size_t BlynkFreeRam()
{
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
#define _BLYNK_USE_DEFAULT_MILLIS
#define _BLYNK_USE_DEFAULT_DELAY
#elif defined(ARDUINO) && defined(__AVR__)
#include <Arduino.h>
void BlynkReset()
{
void(*resetFunc)(void) = 0;
resetFunc();
for(;;) {}
}
size_t BlynkFreeRam()
{
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
#define _BLYNK_USE_DEFAULT_MILLIS
#define _BLYNK_USE_DEFAULT_DELAY
#elif defined(ARDUINO) && defined(ESP8266)
#include <Arduino.h>
size_t BlynkFreeRam()
{
return ESP.getFreeHeap();
}
void BlynkReset()
{
ESP.restart();
for(;;) {}
}
#define _BLYNK_USE_DEFAULT_MILLIS
#define _BLYNK_USE_DEFAULT_DELAY
#elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_SAM)
#include <Arduino.h>
size_t BlynkFreeRam()
{
return 0;
}
void BlynkReset()
{
NVIC_SystemReset();
for(;;) {}
}
#define _BLYNK_USE_DEFAULT_MILLIS
#define _BLYNK_USE_DEFAULT_DELAY
#elif defined (ARDUINO_ARCH_ARC32)
millis_time_t BlynkMillis()
{
// TODO: Remove workaround for Intel Curie
// https://forum.arduino.cc/index.php?topic=391836.0
noInterrupts();
uint64_t t = millis();
interrupts();
return t;
}
#define _BLYNK_USE_DEFAULT_FREE_RAM
#define _BLYNK_USE_DEFAULT_RESET
#define _BLYNK_USE_DEFAULT_DELAY
#elif defined(ARDUINO) && (defined(__STM32F1__) || defined(__STM32F3__))
#include <Arduino.h>
#include <libmaple/nvic.h>
void BlynkReset()
{
nvic_sys_reset();
for(;;) {}
}
#define _BLYNK_USE_DEFAULT_FREE_RAM
#define _BLYNK_USE_DEFAULT_MILLIS
#define _BLYNK_USE_DEFAULT_DELAY
#elif defined (PARTICLE) || defined(SPARK)
#include "application.h"
void BlynkReset()
{
System.reset();
for(;;) {} // To make compiler happy
}
#define _BLYNK_USE_DEFAULT_FREE_RAM
#define _BLYNK_USE_DEFAULT_MILLIS
#define _BLYNK_USE_DEFAULT_DELAY
#elif defined(__MBED__)
#include "mbed.h"
static Timer blynk_millis_timer;
static Ticker blynk_waker;
static
void blynk_wake() {
//pc.puts("(...)");
}
BLYNK_CONSTRUCTOR
static void BlynkSystemInit()
{
blynk_waker.attach(&blynk_wake, 2.0);
blynk_millis_timer.start();
}
void BlynkDelay(millis_time_t ms)
{
wait_ms(ms);
}
millis_time_t BlynkMillis()
{
return blynk_millis_timer.read_ms();
}
#define _BLYNK_USE_DEFAULT_FREE_RAM
#define _BLYNK_USE_DEFAULT_RESET
#elif defined(LINUX) && defined(RASPBERRY)
#include <stdlib.h>
#include <wiringPi.h>
BLYNK_CONSTRUCTOR
static void BlynkSystemInit()
{
wiringPiSetupGpio();
}
void BlynkReset()
{
exit(1);
for(;;) {} // To make compiler happy
}
#define _BLYNK_USE_DEFAULT_FREE_RAM
#define _BLYNK_USE_DEFAULT_MILLIS
#define _BLYNK_USE_DEFAULT_DELAY
#elif defined(LINUX)
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
static millis_time_t blynk_startup_time = 0;
BLYNK_CONSTRUCTOR
static void BlynkSystemInit()
{
blynk_startup_time = BlynkMillis();
}
void BlynkReset()
{
exit(1);
for(;;) {} // To make compiler happy
}
void BlynkDelay(millis_time_t ms)
{
usleep(ms * 1000);
}
millis_time_t BlynkMillis()
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts );
return ( ts.tv_sec * 1000 + ts.tv_nsec / 1000000L ) - blynk_startup_time;
}
#define _BLYNK_USE_DEFAULT_FREE_RAM
#else
#if defined(BLYNK_DEBUG_ALL)
#warning "Need to implement board-specific utilities"
#endif
#define _BLYNK_USE_DEFAULT_FREE_RAM
#define _BLYNK_USE_DEFAULT_RESET
#define _BLYNK_USE_DEFAULT_MILLIS
#define _BLYNK_USE_DEFAULT_DELAY
#endif
#ifdef _BLYNK_USE_DEFAULT_DELAY
void BlynkDelay(millis_time_t ms)
{
return delay(ms);
}
#endif
#ifdef _BLYNK_USE_DEFAULT_MILLIS
millis_time_t BlynkMillis()
{
return millis();
}
#endif
#ifdef _BLYNK_USE_DEFAULT_FREE_RAM
size_t BlynkFreeRam()
{
return 0;
}
#endif
#ifdef _BLYNK_USE_DEFAULT_RESET
void BlynkReset()
{
for(;;) {} // To make compiler happy
}
#endif
void BlynkFatal()
{
BlynkDelay(10000L);
BlynkReset();
}

View File

@@ -0,0 +1,305 @@
/**
* @file BlynkDebug.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Jan 2015
* @brief Debug utilities
*
*/
#ifndef BlynkDebug_h
#define BlynkDebug_h
#include "BlynkConfig.h"
#include <stddef.h>
#ifdef ESP8266
extern "C" {
#include "ets_sys.h"
#include "os_type.h"
#include "mem.h"
}
#else
#include <inttypes.h>
#endif
#if defined(ARDUINO_ARCH_ARC32)
typedef uint64_t millis_time_t;
#else
typedef uint32_t millis_time_t;
#endif
void BlynkDelay(millis_time_t ms);
millis_time_t BlynkMillis();
size_t BlynkFreeRam();
void BlynkReset() BLYNK_NORETURN;
void BlynkFatal() BLYNK_NORETURN;
#if defined(SPARK) || defined(PARTICLE)
#include "application.h"
#endif
#if defined(ARDUINO)
#if ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
#endif
#if defined(LINUX)
#if defined(RASPBERRY)
#include <wiringPi.h>
#endif
#endif
#if !defined(BLYNK_RUN_YIELD)
#if defined(BLYNK_NO_YIELD)
#define BLYNK_RUN_YIELD() {}
#elif defined(SPARK) || defined(PARTICLE)
#define BLYNK_RUN_YIELD() { Particle.process(); }
#elif !defined(ARDUINO) || (ARDUINO < 151)
#define BLYNK_RUN_YIELD() {}
#else
#define BLYNK_RUN_YIELD() { BlynkDelay(0); }
#endif
#endif
#if defined(__AVR__)
#include <avr/pgmspace.h>
#define BLYNK_HAS_PROGMEM
#define BLYNK_PROGMEM PROGMEM
#define BLYNK_F(s) F(s)
#define BLYNK_PSTR(s) PSTR(s)
#else
#define BLYNK_PROGMEM
#define BLYNK_F(s) s
#define BLYNK_PSTR(s) s
#endif
#ifdef ARDUINO_AVR_DIGISPARK
typedef fstr_t __FlashStringHelper;
#endif
#if defined(BLYNK_DEBUG_ALL) && !(__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__))
#warning "Compiler features not enabled -> please contact yor board vendor to enable c++0x"
#endif
// Diagnostic defines
#define BLYNK_FATAL(msg) { BLYNK_LOG1(msg); BlynkFatal(); }
#define BLYNK_LOG_RAM() { BLYNK_LOG2(BLYNK_F("Free RAM: "), BlynkFreeRam()); }
#define BLYNK_LOG_FN() BLYNK_LOG3(BLYNK_F(__FUNCTION__), '@', __LINE__);
#define BLYNK_LOG_TROUBLE(t) BLYNK_LOG2(BLYNK_F("Trouble detected: http://docs.blynk.cc/#troubleshooting-"), t)
#ifndef BLYNK_PRINT
#undef BLYNK_DEBUG
#endif
#ifdef BLYNK_DEBUG_ALL
#define BLYNK_DEBUG
#endif
#ifdef BLYNK_PRINT
#if defined(ARDUINO) || defined(SPARK) || defined(PARTICLE)
#if defined(ARDUINO_ARCH_ARC32)
// This will cause error - on purpose
#define BLYNK_LOG(msg, ...) BLYNK_LOG_UNAVAILABLE(msg, ##__VA_ARGS__)
#else
#define BLYNK_LOG(msg, ...) blynk_dbg_print(BLYNK_PSTR(msg), ##__VA_ARGS__)
#endif
#define BLYNK_LOG1(p1) { BLYNK_LOG_TIME(); BLYNK_PRINT.println(p1); }
#define BLYNK_LOG2(p1,p2) { BLYNK_LOG_TIME(); BLYNK_PRINT.print(p1); BLYNK_PRINT.println(p2); }
#define BLYNK_LOG3(p1,p2,p3) { BLYNK_LOG_TIME(); BLYNK_PRINT.print(p1); BLYNK_PRINT.print(p2); BLYNK_PRINT.println(p3); }
#define BLYNK_LOG4(p1,p2,p3,p4) { BLYNK_LOG_TIME(); BLYNK_PRINT.print(p1); BLYNK_PRINT.print(p2); BLYNK_PRINT.print(p3); BLYNK_PRINT.println(p4); }
#define BLYNK_LOG6(p1,p2,p3,p4,p5,p6) { BLYNK_LOG_TIME(); BLYNK_PRINT.print(p1); BLYNK_PRINT.print(p2); BLYNK_PRINT.print(p3); BLYNK_PRINT.print(p4); BLYNK_PRINT.print(p5); BLYNK_PRINT.println(p6); }
#define BLYNK_LOG_IP(msg, ip) { BLYNK_LOG_TIME(); BLYNK_PRINT.print(BLYNK_F(msg)); \
BLYNK_PRINT.print(ip[0]); BLYNK_PRINT.print('.'); \
BLYNK_PRINT.print(ip[1]); BLYNK_PRINT.print('.'); \
BLYNK_PRINT.print(ip[2]); BLYNK_PRINT.print('.'); \
BLYNK_PRINT.println(ip[3]); }
#define BLYNK_LOG_IP_REV(msg, ip) { BLYNK_LOG_TIME(); BLYNK_PRINT.print(BLYNK_F(msg)); \
BLYNK_PRINT.print(ip[3]); BLYNK_PRINT.print('.'); \
BLYNK_PRINT.print(ip[2]); BLYNK_PRINT.print('.'); \
BLYNK_PRINT.print(ip[1]); BLYNK_PRINT.print('.'); \
BLYNK_PRINT.println(ip[0]); }
static
void BLYNK_LOG_TIME() {
BLYNK_PRINT.print('[');
BLYNK_PRINT.print(BlynkMillis());
BLYNK_PRINT.print(BLYNK_F("] "));
}
#ifdef BLYNK_DEBUG
#include <ctype.h>
#define BLYNK_DBG_BREAK() { for(;;); }
#define BLYNK_ASSERT(expr) { if(!(expr)) { BLYNK_LOG2(BLYNK_F("Assertion failed: "), BLYNK_F(#expr)); BLYNK_DBG_BREAK() } }
static
void BLYNK_DBG_DUMP(const char* msg, const void* addr, size_t len) {
if (len) {
BLYNK_LOG_TIME();
BLYNK_PRINT.print(msg);
int l2 = len;
const uint8_t* octets = (const uint8_t*)addr;
bool prev_print = true;
while (l2--) {
const uint8_t c = *octets++ & 0xFF;
if (c >= 32 && c < 127) {
if (!prev_print) { BLYNK_PRINT.print(']'); }
BLYNK_PRINT.print((char)c);
prev_print = true;
} else {
BLYNK_PRINT.print(prev_print?'[':'|');
if (c < 0x10) { BLYNK_PRINT.print('0'); }
BLYNK_PRINT.print(c, HEX);
prev_print = false;
}
}
if (!prev_print) {
BLYNK_PRINT.print(']');
}
BLYNK_PRINT.println();
}
}
#endif
#if !defined(ARDUINO_ARCH_ARC32)
#include <stdio.h>
#include <stdarg.h>
BLYNK_UNUSED
void blynk_dbg_print(const char* BLYNK_PROGMEM fmt, ...)
{
va_list ap;
va_start(ap, fmt);
char buff[128];
BLYNK_PRINT.print('[');
BLYNK_PRINT.print(BlynkMillis());
BLYNK_PRINT.print(BLYNK_F("] "));
#if defined(__AVR__)
vsnprintf_P(buff, sizeof(buff), fmt, ap);
#else
vsnprintf(buff, sizeof(buff), fmt, ap);
#endif
BLYNK_PRINT.println(buff);
va_end(ap);
}
#endif // ARDUINO_ARCH_ARC32
#elif defined(__MBED__)
#define BLYNK_LOG(msg, ...) { BLYNK_PRINT.printf("[%ld] " msg "\n", BlynkMillis(), ##__VA_ARGS__); }
#define BLYNK_LOG1(p1) { BLYNK_LOG(p1);}
#define BLYNK_LOG2(p1,p2) { BLYNK_LOG(p1,p2);}
#define BLYNK_LOG3(p1,p2,p3) { BLYNK_LOG(p1,p2,p3);}
#define BLYNK_LOG4(p1,p2,p3,p4) { BLYNK_LOG(p1,p2,p3,p4);}
#define BLYNK_LOG6(p1,p2,p3,p4,p5,p6) { BLYNK_LOG(p1,p2,p3,p4,p5,p6);}
#define BLYNK_LOG_TIME() BLYNK_PRINT.printf("[%ld]", BlynkMillis());
#ifdef BLYNK_DEBUG
#define BLYNK_DBG_BREAK() raise(SIGTRAP);
#define BLYNK_ASSERT(expr) assert(expr)
static
void BLYNK_DBG_DUMP(const char* msg, const void* addr, size_t len) {
BLYNK_LOG_TIME();
BLYNK_PRINT.printf(msg);
int l2 = len;
const uint8_t* octets = (const uint8_t*)addr;
bool prev_print = true;
while (l2--) {
const uint8_t c = *octets++ & 0xFF;
if (c >= 32 && c < 127) {
if (!prev_print) { BLYNK_PRINT.putc(']'); }
BLYNK_PRINT.putc((char)c);
prev_print = true;
} else {
BLYNK_PRINT.putc(prev_print?'[':'|');
BLYNK_PRINT.printf("%02x", c);
prev_print = false;
}
}
BLYNK_PRINT.printf("%s\n", prev_print?"":"]");
}
#endif
#elif defined(LINUX)
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <iostream>
using namespace std;
#define BLYNK_LOG(msg, ...) { fprintf(BLYNK_PRINT, "[%ld] " msg "\n", BlynkMillis(), ##__VA_ARGS__); }
#define BLYNK_LOG1(p1) { BLYNK_LOG_TIME(); cout << p1 << endl; }
#define BLYNK_LOG2(p1,p2) { BLYNK_LOG_TIME(); cout << p1 << p2 << endl; }
#define BLYNK_LOG3(p1,p2,p3) { BLYNK_LOG_TIME(); cout << p1 << p2 << p3 << endl; }
#define BLYNK_LOG4(p1,p2,p3,p4) { BLYNK_LOG_TIME(); cout << p1 << p2 << p3 << p4 << endl; }
#define BLYNK_LOG6(p1,p2,p3,p4,p5,p6) { BLYNK_LOG_TIME(); cout << p1 << p2 << p3 << p4 << p5 << p6 << endl; }
#define BLYNK_LOG_TIME() cout << '[' << BlynkMillis() << "] ";
#ifdef BLYNK_DEBUG
#define BLYNK_DBG_BREAK() raise(SIGTRAP);
#define BLYNK_ASSERT(expr) assert(expr)
static
void BLYNK_DBG_DUMP(const char* msg, const void* addr, size_t len) {
BLYNK_LOG_TIME();
fprintf(BLYNK_PRINT, "%s", msg);
int l2 = len;
const uint8_t* octets = (const uint8_t*)addr;
bool prev_print = true;
while (l2--) {
const uint8_t c = *octets++ & 0xFF;
if (c >= 32 && c < 127) {
if (!prev_print) { fputc(']', BLYNK_PRINT); }
fputc((char)c, BLYNK_PRINT);
prev_print = true;
} else {
fputc(prev_print?'[':'|', BLYNK_PRINT);
fprintf(BLYNK_PRINT, "%02x", c);
prev_print = false;
}
}
fprintf(BLYNK_PRINT, "%s\n", prev_print?"":"]");
}
#endif
#else
#warning "Cannot detect platform"
#endif
#endif
#ifndef BLYNK_LOG
#define BLYNK_LOG(...)
#define BLYNK_LOG1(p1)
#define BLYNK_LOG2(p1,p2)
#define BLYNK_LOG3(p1,p2,p3)
#define BLYNK_LOG4(p1,p2,p3,p4)
#define BLYNK_LOG6(p1,p2,p3,p4,p5,p6)
#define BLYNK_LOG_IP(msg, ip)
#define BLYNK_LOG_IP_REV(msg, ip)
#endif
#ifndef BLYNK_DBG_BREAK
#define BLYNK_DBG_BREAK()
#define BLYNK_ASSERT(expr)
#define BLYNK_DBG_DUMP(msg, addr, len)
#endif
#endif

View File

@@ -0,0 +1,268 @@
/**
* @file BlynkDetectDevice.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date May 2016
* @brief
*
*/
#ifndef BlynkDetectDevice_h
#define BlynkDetectDevice_h
// General defines
#define BLYNK_NEWLINE "\r\n"
#define BLYNK_CONCAT(a, b) a ## b
#define BLYNK_CONCAT2(a, b) BLYNK_CONCAT(a, b)
#define BLYNK_STRINGIFY(x) #x
#define BLYNK_TOSTRING(x) BLYNK_STRINGIFY(x)
#define BLYNK_COUNT_OF(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x])))))
#define BLYNK_ATTR_PACKED __attribute__ ((__packed__))
#define BLYNK_NORETURN __attribute__ ((noreturn))
#define BLYNK_UNUSED __attribute__((__unused__))
#define BLYNK_DEPRECATED __attribute__ ((deprecated))
#define BLYNK_CONSTRUCTOR __attribute__((constructor))
// Causes problems on some platforms
#define BLYNK_FORCE_INLINE inline //__attribute__((always_inline))
#ifndef BLYNK_INFO_CPU
#if defined(__AVR_ATmega168__)
#define BLYNK_INFO_CPU "ATmega168"
#endif
#endif
#ifndef BLYNK_INFO_DEVICE
#if defined(ENERGIA)
#define BLYNK_NO_YIELD
#define BLYNK_USE_128_VPINS
#if defined(ENERGIA_ARCH_MSP430)
#define BLYNK_INFO_DEVICE "LaunchPad MSP430"
#define BLYNK_INFO_CPU "MSP430"
#define BLYNK_NO_FLOAT
#elif defined(ENERGIA_ARCH_MSP432)
#define BLYNK_INFO_DEVICE "LaunchPad MSP432"
#define BLYNK_INFO_CPU "MSP432"
#elif defined(ENERGIA_ARCH_TIVAC)
#define BLYNK_INFO_DEVICE "LaunchPad"
#elif defined(ENERGIA_ARCH_CC3200EMT) || defined(ENERGIA_ARCH_CC3200)
#define BLYNK_INFO_CONNECTION "CC3200"
#define BLYNK_SEND_CHUNK 64
#define BLYNK_BUFFERS_SIZE 1024
#if defined(ENERGIA_CC3200_LAUNCHXL) //TODO: This is a bug in Energia IDE
#define BLYNK_INFO_DEVICE "CC3200 LaunchXL"
#elif defined(ENERGIA_RedBearLab_CC3200)
#define BLYNK_INFO_DEVICE "RBL CC3200"
#elif defined(ENERGIA_RedBearLab_WiFiMini)
#define BLYNK_INFO_DEVICE "RBL WiFi Mini"
#elif defined(ENERGIA_RedBearLab_WiFiMicro)
#define BLYNK_INFO_DEVICE "RBL WiFi Micro"
#endif
#elif defined(ENERGIA_ARCH_CC3220EMT) || defined(ENERGIA_ARCH_CC3220)
#define BLYNK_INFO_CONNECTION "CC3220"
#define BLYNK_SEND_CHUNK 64
#define BLYNK_BUFFERS_SIZE 1024
#define BLYNK_USE_INTERNAL_DTOSTRF
#define BLYNK_INFO_DEVICE "CC3220"
#define BLYNK_INFO_CPU "CC3220"
#endif
#if !defined(BLYNK_INFO_DEVICE)
#define BLYNK_INFO_DEVICE "Energia"
#endif
#elif defined(LINUX)
#define BLYNK_INFO_DEVICE "Linux"
#define BLYNK_USE_128_VPINS
#define BLYNK_BUFFERS_SIZE 4096
#elif defined(SPARK) || defined(PARTICLE)
#define BLYNK_USE_128_VPINS
#define BLYNK_BUFFERS_SIZE 1024
#if PLATFORM_ID==0
#define BLYNK_INFO_DEVICE "Particle Core"
#undef BLYNK_BUFFERS_SIZE // Use default on Core
#elif PLATFORM_ID==6
#define BLYNK_INFO_DEVICE "Particle Photon"
#elif PLATFORM_ID==8
#define BLYNK_INFO_DEVICE "Particle P1"
#elif PLATFORM_ID==9
#define BLYNK_INFO_DEVICE "Particle Ethernet"
#elif PLATFORM_ID==10
#define BLYNK_INFO_DEVICE "Particle Electron"
#elif PLATFORM_ID==31
#define BLYNK_INFO_DEVICE "Particle RPi"
#elif PLATFORM_ID==82
#define BLYNK_INFO_DEVICE "Digistump Oak"
#elif PLATFORM_ID==88
#define BLYNK_INFO_DEVICE "RedBear Duo"
#elif PLATFORM_ID==103
#define BLYNK_INFO_DEVICE "Bluz"
#else
#if defined(BLYNK_DEBUG_ALL)
#warning "Cannot detect board type"
#endif
#define BLYNK_INFO_DEVICE "Particle"
#endif
#elif defined(__MBED__)
#define BLYNK_INFO_DEVICE "MBED"
#define BLYNK_USE_128_VPINS
#define BLYNK_BUFFERS_SIZE 512
#define noInterrupts() __disable_irq()
#define interrupts() __enable_irq()
#elif defined(ARDUINO) && defined(MPIDE)
#define BLYNK_NO_YIELD
#if defined(_BOARD_UNO_)
#define BLYNK_INFO_DEVICE "chipKIT Uno32"
#else
#define BLYNK_INFO_DEVICE "chipKIT"
#endif
#elif defined(ARDUINO) && defined(ARDUINO_AMEBA)
#if defined(BOARD_RTL8710)
#define BLYNK_INFO_DEVICE "RTL8710"
#define BLYNK_USE_128_VPINS
#define BLYNK_BUFFERS_SIZE 1024
#elif defined(BOARD_RTL8711AM)
#define BLYNK_INFO_DEVICE "RTL8711AM"
#define BLYNK_USE_128_VPINS
#define BLYNK_BUFFERS_SIZE 1024
#elif defined(BOARD_RTL8195A)
#define BLYNK_INFO_DEVICE "RTL8195A"
#define BLYNK_USE_128_VPINS
#define BLYNK_BUFFERS_SIZE 1024
#else
#define BLYNK_INFO_DEVICE "Ameba"
#endif
#elif defined(ARDUINO) && defined(TEENSYDUINO)
#if defined(__MK66FX1M0__)
#define BLYNK_INFO_DEVICE "Teensy 3.6"
#define BLYNK_USE_128_VPINS
#define BLYNK_BUFFERS_SIZE 1024
#elif defined(__MK64FX512__)
#define BLYNK_INFO_DEVICE "Teensy 3.5"
#define BLYNK_USE_128_VPINS
#define BLYNK_BUFFERS_SIZE 1024
#elif defined(__MK20DX256__)
#define BLYNK_INFO_DEVICE "Teensy 3.2/3.1"
#define BLYNK_USE_128_VPINS
#define BLYNK_BUFFERS_SIZE 1024
#elif defined(__MK20DX128__)
#define BLYNK_INFO_DEVICE "Teensy 3.0"
#define BLYNK_USE_128_VPINS
#define BLYNK_BUFFERS_SIZE 1024
#elif defined(__MKL26Z64__)
#define BLYNK_INFO_DEVICE "Teensy LC"
#define BLYNK_BUFFERS_SIZE 512
#elif defined(ARDUINO_ARCH_AVR)
#define BLYNK_INFO_DEVICE "Teensy 2.0"
#else
#define BLYNK_INFO_DEVICE "Teensy"
#endif
#elif defined(ARDUINO)
#if defined(ARDUINO_ARCH_SAMD) || defined(ESP32) || defined(ESP8266)
#define BLYNK_USE_128_VPINS
#define BLYNK_BUFFERS_SIZE 1024
#endif
/* Arduino AVR */
#if defined(ARDUINO_AVR_NANO)
#define BLYNK_INFO_DEVICE "Arduino Nano"
/* ESP8266 */
#elif defined(ARDUINO_ESP8266_ESP01)
#define BLYNK_INFO_DEVICE "ESP8266"
#elif defined(ARDUINO_ESP8266_ESP12)
#define BLYNK_INFO_DEVICE "ESP-12"
#elif defined(ARDUINO_ESP8266_NODEMCU)
#define BLYNK_INFO_DEVICE "NodeMCU"
#elif defined(ARDUINO_ESP8266_THING)
#define BLYNK_INFO_DEVICE "Esp Thing"
#elif defined(ARDUINO_ESP8266_THING_DEV)
#define BLYNK_INFO_DEVICE "Esp Thing Dev"
/* ESP32 */
#elif defined(ARDUINO_ESP32_DEV)
#define BLYNK_INFO_DEVICE "ESP32"
#elif defined(ARDUINO_ESP320)
#define BLYNK_INFO_DEVICE "SweetPeas ESP320"
#elif defined(ARDUINO_NANO32)
#define BLYNK_INFO_DEVICE "ESP32 Nano32"
#elif defined(ARDUINO_LoLin32)
#define BLYNK_INFO_DEVICE "LoLin32"
#elif defined(ARDUINO_ESPea32)
#define BLYNK_INFO_DEVICE "ESPea32"
#elif defined(ARDUINO_QUANTUM)
#define BLYNK_INFO_DEVICE "Noduino Quantum"
#else
#if defined(BLYNK_DEBUG_ALL)
#warning "Cannot detect board type"
#endif
#define BLYNK_INFO_DEVICE "Arduino"
#endif
#elif defined(TI_CC3220)
#define BLYNK_INFO_DEVICE "TI CC3220"
#define BLYNK_USE_128_VPINS
#define BLYNK_BUFFERS_SIZE 1024
#define BLYNK_USE_INTERNAL_DTOSTRF
#else
#define BLYNK_INFO_DEVICE "Custom platform"
#endif
#if !defined(BLYNK_MAX_READBYTES) && defined(BLYNK_BUFFERS_SIZE)
#define BLYNK_MAX_READBYTES BLYNK_BUFFERS_SIZE
#endif
#if !defined(BLYNK_MAX_SENDBYTES) && defined(BLYNK_BUFFERS_SIZE)
#define BLYNK_MAX_SENDBYTES BLYNK_BUFFERS_SIZE
#endif
// Print diagnostics
#if defined(BLYNK_DEBUG_ALL)
#if defined(BLYNK_INFO_DEVICE)
#pragma message ("BLYNK_INFO_DEVICE=" BLYNK_TOSTRING(BLYNK_INFO_DEVICE))
#endif
#if defined(BLYNK_INFO_CPU)
#pragma message ("BLYNK_INFO_CPU=" BLYNK_TOSTRING(BLYNK_INFO_CPU))
#endif
#if defined(BLYNK_BUFFERS_SIZE)
#pragma message ("BLYNK_BUFFERS_SIZE=" BLYNK_TOSTRING(BLYNK_BUFFERS_SIZE))
#endif
#endif
#endif
#endif

View File

@@ -0,0 +1,69 @@
#ifndef BLYNKEVERYN_H
#define BLYNKEVERYN_H
#include "BlynkDebug.h"
millis_time_t blynk_count_millis() {
const millis_time_t ms = BlynkMillis();
return ms;
}
uint16_t blynk_count_seconds16() {
const millis_time_t ms = BlynkMillis();
return (ms / 1000);
}
uint16_t blynk_count_minutes16()
{
const millis_time_t ms = BlynkMillis();
return (ms / (60000L)) & 0xFFFF;
}
uint8_t blynk_count_hours8()
{
const millis_time_t ms = BlynkMillis();
return (ms / (3600000L)) & 0xFF;
}
template<typename T, T (*timeGetter)()>
class BlynkPeriodic {
public:
T mPrev;
T mPeriod;
BlynkPeriodic() { reset(); mPeriod = 1; };
BlynkPeriodic(T period) { reset(); setPeriod(period); };
void setPeriod( T period) { mPeriod = period; };
T getTime() { return (T)(timeGetter()); };
T getPeriod() { return mPeriod; };
T getElapsed() { return getTime() - mPrev; }
T getRemaining() { return mPeriod - getElapsed(); }
T getLastTriggerTime() { return mPrev; }
bool ready() {
bool isReady = (getElapsed() >= mPeriod);
if( isReady ) { reset(); }
return isReady;
}
void reset() { mPrev = getTime(); };
void trigger() { mPrev = getTime() - mPeriod; };
operator bool() { return ready(); }
};
typedef BlynkPeriodic<millis_time_t,blynk_count_millis> BlynkEveryNMillis;
typedef BlynkPeriodic<uint16_t,blynk_count_seconds16> BlynkEveryNSeconds;
typedef BlynkPeriodic<uint16_t,blynk_count_minutes16> BlynkEveryNMinutes;
typedef BlynkPeriodic<uint8_t,blynk_count_hours8> BlynkEveryNHours;
#define BLYNK_EVERY_N_MILLIS_I(NAME,N) static BlynkEveryNMillis NAME(N); if(NAME)
#define BLYNK_EVERY_N_SECONDS_I(NAME,N) static BlynkEveryNSeconds NAME(N); if(NAME)
#define BLYNK_EVERY_N_MINUTES_I(NAME,N) static BlynkEveryNMinutes NAME(N); if(NAME)
#define BLYNK_EVERY_N_HOURS_I(NAME,N) static BlynkEveryNHours NAME(N); if(NAME)
#define BLYNK_EVERY_N_MILLIS(N) BLYNK_EVERY_N_MILLIS_I(BLYNK_CONCAT2(PER, __COUNTER__),N)
#define BLYNK_EVERY_N_SECONDS(N) BLYNK_EVERY_N_SECONDS_I(BLYNK_CONCAT2(PER, __COUNTER__),N)
#define BLYNK_EVERY_N_MINUTES(N) BLYNK_EVERY_N_MINUTES_I(BLYNK_CONCAT2(PER, __COUNTER__),N)
#define BLYNK_EVERY_N_HOURS(N) BLYNK_EVERY_N_HOURS_I(BLYNK_CONCAT2(PER, __COUNTER__),N)
#endif

View File

@@ -0,0 +1,158 @@
/**
* @file BlynkFifo.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Feb 2015
* @brief FIFO implementation
*
*/
#ifndef BlynkFifo_h
#define BlynkFifo_h
#include "BlynkUtility.h"
template <class T, unsigned N>
class BlynkFifo
{
public:
BlynkFifo()
{
clear();
}
void clear()
{
_r = 0;
_w = 0;
}
~BlynkFifo(void)
{}
// writing thread/context API
//-------------------------------------------------------------
bool writeable(void)
{
return free() > 0;
}
int free(void)
{
int s = _r - _w;
if (s <= 0)
s += N;
return s - 1;
}
T put(const T& c)
{
int i = _w;
int j = i;
i = _inc(i);
while (i == _r) // = !writeable()
/* nothing / just wait */;
_b[j] = c;
_w = i;
return c;
}
int put(const T* p, int n, bool blocking = false)
{
int c = n;
while (c)
{
int f;
while ((f = free()) == 0) // wait for space
{
if (!blocking) return n - c; // no more space and not blocking
/* nothing / just wait */;
}
// check free space
if (c < f) f = c;
int w = _w;
int m = N - w;
// check wrap
if (f > m) f = m;
memcpy(&_b[w], p, f);
_w = _inc(w, f);
c -= f;
p += f;
}
return n - c;
}
// reading thread/context API
// --------------------------------------------------------
bool readable(void)
{
return (_r != _w);
}
size_t size(void)
{
int s = _w - _r;
if (s < 0)
s += N;
return s;
}
T get(void)
{
int r = _r;
while (r == _w) // = !readable()
/* nothing / just wait */;
T t = _b[r];
_r = _inc(r);
return t;
}
T peek(void)
{
int r = _r;
while (r == _w);
return _b[r];
}
int get(T* p, int n, bool blocking = false)
{
int c = n;
while (c)
{
int f;
for (;;) // wait for data
{
f = size();
if (f) break; // free space
if (!blocking) return n - c; // no space and not blocking
/* nothing / just wait */;
}
// check available data
if (c < f) f = c;
int r = _r;
int m = N - r;
// check wrap
if (f > m) f = m;
memcpy(p, &_b[r], f);
_r = _inc(r, f);
c -= f;
p += f;
}
return n - c;
}
private:
int _inc(int i, int n = 1)
{
return (i + n) % N;
}
T _b[N];
volatile int _w;
volatile int _r;
};
#endif

View File

@@ -0,0 +1,402 @@
/**
* @file BlynkHandlers.cpp
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Jan 2015
* @brief Virtual pin utilities
*/
#include "BlynkConfig.h"
#include "BlynkHandlers.h"
#include "BlynkDebug.h"
void BlynkNoOpCbk()
{}
void BlynkWidgetRead(BlynkReq BLYNK_UNUSED &request)
{
BLYNK_LOG2(BLYNK_F("No handler for reading from pin "), request.pin);
}
void BlynkWidgetWrite(BlynkReq BLYNK_UNUSED &request, const BlynkParam BLYNK_UNUSED &param)
{
BLYNK_LOG2(BLYNK_F("No handler for writing to pin "), request.pin);
}
#define BLYNK_ON_READ_IMPL(pin) void BlynkWidgetRead ## pin (BlynkReq BLYNK_UNUSED &req) \
__attribute__((weak, alias("BlynkWidgetRead")))
#define BLYNK_ON_WRITE_IMPL(pin) void BlynkWidgetWrite ## pin (BlynkReq BLYNK_UNUSED &req, const BlynkParam BLYNK_UNUSED &param) \
__attribute__((weak, alias("BlynkWidgetWrite")))
BLYNK_CONNECTED() __attribute__((weak, alias("BlynkNoOpCbk")));
BLYNK_DISCONNECTED() __attribute__((weak, alias("BlynkNoOpCbk")));
// Internal Virtual Pins
BLYNK_ON_WRITE_IMPL(InternalPinACON);
BLYNK_ON_WRITE_IMPL(InternalPinADIS);
BLYNK_ON_WRITE_IMPL(InternalPinRTC);
BLYNK_ON_WRITE_IMPL(InternalPinOTA);
// Regular Virtual Pins
BLYNK_ON_READ_IMPL(Default);
BLYNK_ON_WRITE_IMPL(Default);
BLYNK_ON_READ_IMPL(0 );
BLYNK_ON_READ_IMPL(1 );
BLYNK_ON_READ_IMPL(2 );
BLYNK_ON_READ_IMPL(3 );
BLYNK_ON_READ_IMPL(4 );
BLYNK_ON_READ_IMPL(5 );
BLYNK_ON_READ_IMPL(6 );
BLYNK_ON_READ_IMPL(7 );
BLYNK_ON_READ_IMPL(8 );
BLYNK_ON_READ_IMPL(9 );
BLYNK_ON_READ_IMPL(10);
BLYNK_ON_READ_IMPL(11);
BLYNK_ON_READ_IMPL(12);
BLYNK_ON_READ_IMPL(13);
BLYNK_ON_READ_IMPL(14);
BLYNK_ON_READ_IMPL(15);
BLYNK_ON_READ_IMPL(16);
BLYNK_ON_READ_IMPL(17);
BLYNK_ON_READ_IMPL(18);
BLYNK_ON_READ_IMPL(19);
BLYNK_ON_READ_IMPL(20);
BLYNK_ON_READ_IMPL(21);
BLYNK_ON_READ_IMPL(22);
BLYNK_ON_READ_IMPL(23);
BLYNK_ON_READ_IMPL(24);
BLYNK_ON_READ_IMPL(25);
BLYNK_ON_READ_IMPL(26);
BLYNK_ON_READ_IMPL(27);
BLYNK_ON_READ_IMPL(28);
BLYNK_ON_READ_IMPL(29);
BLYNK_ON_READ_IMPL(30);
BLYNK_ON_READ_IMPL(31);
#ifdef BLYNK_USE_128_VPINS
BLYNK_ON_READ_IMPL(32);
BLYNK_ON_READ_IMPL(33);
BLYNK_ON_READ_IMPL(34);
BLYNK_ON_READ_IMPL(35);
BLYNK_ON_READ_IMPL(36);
BLYNK_ON_READ_IMPL(37);
BLYNK_ON_READ_IMPL(38);
BLYNK_ON_READ_IMPL(39);
BLYNK_ON_READ_IMPL(40);
BLYNK_ON_READ_IMPL(41);
BLYNK_ON_READ_IMPL(42);
BLYNK_ON_READ_IMPL(43);
BLYNK_ON_READ_IMPL(44);
BLYNK_ON_READ_IMPL(45);
BLYNK_ON_READ_IMPL(46);
BLYNK_ON_READ_IMPL(47);
BLYNK_ON_READ_IMPL(48);
BLYNK_ON_READ_IMPL(49);
BLYNK_ON_READ_IMPL(50);
BLYNK_ON_READ_IMPL(51);
BLYNK_ON_READ_IMPL(52);
BLYNK_ON_READ_IMPL(53);
BLYNK_ON_READ_IMPL(54);
BLYNK_ON_READ_IMPL(55);
BLYNK_ON_READ_IMPL(56);
BLYNK_ON_READ_IMPL(57);
BLYNK_ON_READ_IMPL(58);
BLYNK_ON_READ_IMPL(59);
BLYNK_ON_READ_IMPL(60);
BLYNK_ON_READ_IMPL(61);
BLYNK_ON_READ_IMPL(62);
BLYNK_ON_READ_IMPL(63);
BLYNK_ON_READ_IMPL(64);
BLYNK_ON_READ_IMPL(65);
BLYNK_ON_READ_IMPL(66);
BLYNK_ON_READ_IMPL(67);
BLYNK_ON_READ_IMPL(68);
BLYNK_ON_READ_IMPL(69);
BLYNK_ON_READ_IMPL(70);
BLYNK_ON_READ_IMPL(71);
BLYNK_ON_READ_IMPL(72);
BLYNK_ON_READ_IMPL(73);
BLYNK_ON_READ_IMPL(74);
BLYNK_ON_READ_IMPL(75);
BLYNK_ON_READ_IMPL(76);
BLYNK_ON_READ_IMPL(77);
BLYNK_ON_READ_IMPL(78);
BLYNK_ON_READ_IMPL(79);
BLYNK_ON_READ_IMPL(80);
BLYNK_ON_READ_IMPL(81);
BLYNK_ON_READ_IMPL(82);
BLYNK_ON_READ_IMPL(83);
BLYNK_ON_READ_IMPL(84);
BLYNK_ON_READ_IMPL(85);
BLYNK_ON_READ_IMPL(86);
BLYNK_ON_READ_IMPL(87);
BLYNK_ON_READ_IMPL(88);
BLYNK_ON_READ_IMPL(89);
BLYNK_ON_READ_IMPL(90);
BLYNK_ON_READ_IMPL(91);
BLYNK_ON_READ_IMPL(92);
BLYNK_ON_READ_IMPL(93);
BLYNK_ON_READ_IMPL(94);
BLYNK_ON_READ_IMPL(95);
BLYNK_ON_READ_IMPL(96);
BLYNK_ON_READ_IMPL(97);
BLYNK_ON_READ_IMPL(98);
BLYNK_ON_READ_IMPL(99);
BLYNK_ON_READ_IMPL(100);
BLYNK_ON_READ_IMPL(101);
BLYNK_ON_READ_IMPL(102);
BLYNK_ON_READ_IMPL(103);
BLYNK_ON_READ_IMPL(104);
BLYNK_ON_READ_IMPL(105);
BLYNK_ON_READ_IMPL(106);
BLYNK_ON_READ_IMPL(107);
BLYNK_ON_READ_IMPL(108);
BLYNK_ON_READ_IMPL(109);
BLYNK_ON_READ_IMPL(110);
BLYNK_ON_READ_IMPL(111);
BLYNK_ON_READ_IMPL(112);
BLYNK_ON_READ_IMPL(113);
BLYNK_ON_READ_IMPL(114);
BLYNK_ON_READ_IMPL(115);
BLYNK_ON_READ_IMPL(116);
BLYNK_ON_READ_IMPL(117);
BLYNK_ON_READ_IMPL(118);
BLYNK_ON_READ_IMPL(119);
BLYNK_ON_READ_IMPL(120);
BLYNK_ON_READ_IMPL(121);
BLYNK_ON_READ_IMPL(122);
BLYNK_ON_READ_IMPL(123);
BLYNK_ON_READ_IMPL(124);
BLYNK_ON_READ_IMPL(125);
BLYNK_ON_READ_IMPL(126);
BLYNK_ON_READ_IMPL(127);
#endif
BLYNK_ON_WRITE_IMPL(0 );
BLYNK_ON_WRITE_IMPL(1 );
BLYNK_ON_WRITE_IMPL(2 );
BLYNK_ON_WRITE_IMPL(3 );
BLYNK_ON_WRITE_IMPL(4 );
BLYNK_ON_WRITE_IMPL(5 );
BLYNK_ON_WRITE_IMPL(6 );
BLYNK_ON_WRITE_IMPL(7 );
BLYNK_ON_WRITE_IMPL(8 );
BLYNK_ON_WRITE_IMPL(9 );
BLYNK_ON_WRITE_IMPL(10);
BLYNK_ON_WRITE_IMPL(11);
BLYNK_ON_WRITE_IMPL(12);
BLYNK_ON_WRITE_IMPL(13);
BLYNK_ON_WRITE_IMPL(14);
BLYNK_ON_WRITE_IMPL(15);
BLYNK_ON_WRITE_IMPL(16);
BLYNK_ON_WRITE_IMPL(17);
BLYNK_ON_WRITE_IMPL(18);
BLYNK_ON_WRITE_IMPL(19);
BLYNK_ON_WRITE_IMPL(20);
BLYNK_ON_WRITE_IMPL(21);
BLYNK_ON_WRITE_IMPL(22);
BLYNK_ON_WRITE_IMPL(23);
BLYNK_ON_WRITE_IMPL(24);
BLYNK_ON_WRITE_IMPL(25);
BLYNK_ON_WRITE_IMPL(26);
BLYNK_ON_WRITE_IMPL(27);
BLYNK_ON_WRITE_IMPL(28);
BLYNK_ON_WRITE_IMPL(29);
BLYNK_ON_WRITE_IMPL(30);
BLYNK_ON_WRITE_IMPL(31);
#ifdef BLYNK_USE_128_VPINS
BLYNK_ON_WRITE_IMPL(32);
BLYNK_ON_WRITE_IMPL(33);
BLYNK_ON_WRITE_IMPL(34);
BLYNK_ON_WRITE_IMPL(35);
BLYNK_ON_WRITE_IMPL(36);
BLYNK_ON_WRITE_IMPL(37);
BLYNK_ON_WRITE_IMPL(38);
BLYNK_ON_WRITE_IMPL(39);
BLYNK_ON_WRITE_IMPL(40);
BLYNK_ON_WRITE_IMPL(41);
BLYNK_ON_WRITE_IMPL(42);
BLYNK_ON_WRITE_IMPL(43);
BLYNK_ON_WRITE_IMPL(44);
BLYNK_ON_WRITE_IMPL(45);
BLYNK_ON_WRITE_IMPL(46);
BLYNK_ON_WRITE_IMPL(47);
BLYNK_ON_WRITE_IMPL(48);
BLYNK_ON_WRITE_IMPL(49);
BLYNK_ON_WRITE_IMPL(50);
BLYNK_ON_WRITE_IMPL(51);
BLYNK_ON_WRITE_IMPL(52);
BLYNK_ON_WRITE_IMPL(53);
BLYNK_ON_WRITE_IMPL(54);
BLYNK_ON_WRITE_IMPL(55);
BLYNK_ON_WRITE_IMPL(56);
BLYNK_ON_WRITE_IMPL(57);
BLYNK_ON_WRITE_IMPL(58);
BLYNK_ON_WRITE_IMPL(59);
BLYNK_ON_WRITE_IMPL(60);
BLYNK_ON_WRITE_IMPL(61);
BLYNK_ON_WRITE_IMPL(62);
BLYNK_ON_WRITE_IMPL(63);
BLYNK_ON_WRITE_IMPL(64);
BLYNK_ON_WRITE_IMPL(65);
BLYNK_ON_WRITE_IMPL(66);
BLYNK_ON_WRITE_IMPL(67);
BLYNK_ON_WRITE_IMPL(68);
BLYNK_ON_WRITE_IMPL(69);
BLYNK_ON_WRITE_IMPL(70);
BLYNK_ON_WRITE_IMPL(71);
BLYNK_ON_WRITE_IMPL(72);
BLYNK_ON_WRITE_IMPL(73);
BLYNK_ON_WRITE_IMPL(74);
BLYNK_ON_WRITE_IMPL(75);
BLYNK_ON_WRITE_IMPL(76);
BLYNK_ON_WRITE_IMPL(77);
BLYNK_ON_WRITE_IMPL(78);
BLYNK_ON_WRITE_IMPL(79);
BLYNK_ON_WRITE_IMPL(80);
BLYNK_ON_WRITE_IMPL(81);
BLYNK_ON_WRITE_IMPL(82);
BLYNK_ON_WRITE_IMPL(83);
BLYNK_ON_WRITE_IMPL(84);
BLYNK_ON_WRITE_IMPL(85);
BLYNK_ON_WRITE_IMPL(86);
BLYNK_ON_WRITE_IMPL(87);
BLYNK_ON_WRITE_IMPL(88);
BLYNK_ON_WRITE_IMPL(89);
BLYNK_ON_WRITE_IMPL(90);
BLYNK_ON_WRITE_IMPL(91);
BLYNK_ON_WRITE_IMPL(92);
BLYNK_ON_WRITE_IMPL(93);
BLYNK_ON_WRITE_IMPL(94);
BLYNK_ON_WRITE_IMPL(95);
BLYNK_ON_WRITE_IMPL(96);
BLYNK_ON_WRITE_IMPL(97);
BLYNK_ON_WRITE_IMPL(98);
BLYNK_ON_WRITE_IMPL(99);
BLYNK_ON_WRITE_IMPL(100);
BLYNK_ON_WRITE_IMPL(101);
BLYNK_ON_WRITE_IMPL(102);
BLYNK_ON_WRITE_IMPL(103);
BLYNK_ON_WRITE_IMPL(104);
BLYNK_ON_WRITE_IMPL(105);
BLYNK_ON_WRITE_IMPL(106);
BLYNK_ON_WRITE_IMPL(107);
BLYNK_ON_WRITE_IMPL(108);
BLYNK_ON_WRITE_IMPL(109);
BLYNK_ON_WRITE_IMPL(110);
BLYNK_ON_WRITE_IMPL(111);
BLYNK_ON_WRITE_IMPL(112);
BLYNK_ON_WRITE_IMPL(113);
BLYNK_ON_WRITE_IMPL(114);
BLYNK_ON_WRITE_IMPL(115);
BLYNK_ON_WRITE_IMPL(116);
BLYNK_ON_WRITE_IMPL(117);
BLYNK_ON_WRITE_IMPL(118);
BLYNK_ON_WRITE_IMPL(119);
BLYNK_ON_WRITE_IMPL(120);
BLYNK_ON_WRITE_IMPL(121);
BLYNK_ON_WRITE_IMPL(122);
BLYNK_ON_WRITE_IMPL(123);
BLYNK_ON_WRITE_IMPL(124);
BLYNK_ON_WRITE_IMPL(125);
BLYNK_ON_WRITE_IMPL(126);
BLYNK_ON_WRITE_IMPL(127);
#endif
static const WidgetReadHandler BlynkReadHandlerVector[] BLYNK_PROGMEM = {
BlynkWidgetRead0, BlynkWidgetRead1, BlynkWidgetRead2, BlynkWidgetRead3,
BlynkWidgetRead4, BlynkWidgetRead5, BlynkWidgetRead6, BlynkWidgetRead7,
BlynkWidgetRead8, BlynkWidgetRead9, BlynkWidgetRead10, BlynkWidgetRead11,
BlynkWidgetRead12, BlynkWidgetRead13, BlynkWidgetRead14, BlynkWidgetRead15,
BlynkWidgetRead16, BlynkWidgetRead17, BlynkWidgetRead18, BlynkWidgetRead19,
BlynkWidgetRead20, BlynkWidgetRead21, BlynkWidgetRead22, BlynkWidgetRead23,
BlynkWidgetRead24, BlynkWidgetRead25, BlynkWidgetRead26, BlynkWidgetRead27,
BlynkWidgetRead28, BlynkWidgetRead29, BlynkWidgetRead30, BlynkWidgetRead31,
#ifdef BLYNK_USE_128_VPINS
BlynkWidgetRead32, BlynkWidgetRead33, BlynkWidgetRead34, BlynkWidgetRead35,
BlynkWidgetRead36, BlynkWidgetRead37, BlynkWidgetRead38, BlynkWidgetRead39,
BlynkWidgetRead40, BlynkWidgetRead41, BlynkWidgetRead42, BlynkWidgetRead43,
BlynkWidgetRead44, BlynkWidgetRead45, BlynkWidgetRead46, BlynkWidgetRead47,
BlynkWidgetRead48, BlynkWidgetRead49, BlynkWidgetRead50, BlynkWidgetRead51,
BlynkWidgetRead52, BlynkWidgetRead53, BlynkWidgetRead54, BlynkWidgetRead55,
BlynkWidgetRead56, BlynkWidgetRead57, BlynkWidgetRead58, BlynkWidgetRead59,
BlynkWidgetRead60, BlynkWidgetRead61, BlynkWidgetRead62, BlynkWidgetRead63,
BlynkWidgetRead64, BlynkWidgetRead65, BlynkWidgetRead66, BlynkWidgetRead67,
BlynkWidgetRead68, BlynkWidgetRead69, BlynkWidgetRead70, BlynkWidgetRead71,
BlynkWidgetRead72, BlynkWidgetRead73, BlynkWidgetRead74, BlynkWidgetRead75,
BlynkWidgetRead76, BlynkWidgetRead77, BlynkWidgetRead78, BlynkWidgetRead79,
BlynkWidgetRead80, BlynkWidgetRead81, BlynkWidgetRead82, BlynkWidgetRead83,
BlynkWidgetRead84, BlynkWidgetRead85, BlynkWidgetRead86, BlynkWidgetRead87,
BlynkWidgetRead88, BlynkWidgetRead89, BlynkWidgetRead90, BlynkWidgetRead91,
BlynkWidgetRead92, BlynkWidgetRead93, BlynkWidgetRead94, BlynkWidgetRead95,
BlynkWidgetRead96, BlynkWidgetRead97, BlynkWidgetRead98, BlynkWidgetRead99,
BlynkWidgetRead100, BlynkWidgetRead101, BlynkWidgetRead102, BlynkWidgetRead103,
BlynkWidgetRead104, BlynkWidgetRead105, BlynkWidgetRead106, BlynkWidgetRead107,
BlynkWidgetRead108, BlynkWidgetRead109, BlynkWidgetRead110, BlynkWidgetRead111,
BlynkWidgetRead112, BlynkWidgetRead113, BlynkWidgetRead114, BlynkWidgetRead115,
BlynkWidgetRead116, BlynkWidgetRead117, BlynkWidgetRead118, BlynkWidgetRead119,
BlynkWidgetRead120, BlynkWidgetRead121, BlynkWidgetRead122, BlynkWidgetRead123,
BlynkWidgetRead124, BlynkWidgetRead125, BlynkWidgetRead126, BlynkWidgetRead127,
#endif
};
static const WidgetWriteHandler BlynkWriteHandlerVector[] BLYNK_PROGMEM = {
BlynkWidgetWrite0, BlynkWidgetWrite1, BlynkWidgetWrite2, BlynkWidgetWrite3,
BlynkWidgetWrite4, BlynkWidgetWrite5, BlynkWidgetWrite6, BlynkWidgetWrite7,
BlynkWidgetWrite8, BlynkWidgetWrite9, BlynkWidgetWrite10, BlynkWidgetWrite11,
BlynkWidgetWrite12, BlynkWidgetWrite13, BlynkWidgetWrite14, BlynkWidgetWrite15,
BlynkWidgetWrite16, BlynkWidgetWrite17, BlynkWidgetWrite18, BlynkWidgetWrite19,
BlynkWidgetWrite20, BlynkWidgetWrite21, BlynkWidgetWrite22, BlynkWidgetWrite23,
BlynkWidgetWrite24, BlynkWidgetWrite25, BlynkWidgetWrite26, BlynkWidgetWrite27,
BlynkWidgetWrite28, BlynkWidgetWrite29, BlynkWidgetWrite30, BlynkWidgetWrite31,
#ifdef BLYNK_USE_128_VPINS
BlynkWidgetWrite32, BlynkWidgetWrite33, BlynkWidgetWrite34, BlynkWidgetWrite35,
BlynkWidgetWrite36, BlynkWidgetWrite37, BlynkWidgetWrite38, BlynkWidgetWrite39,
BlynkWidgetWrite40, BlynkWidgetWrite41, BlynkWidgetWrite42, BlynkWidgetWrite43,
BlynkWidgetWrite44, BlynkWidgetWrite45, BlynkWidgetWrite46, BlynkWidgetWrite47,
BlynkWidgetWrite48, BlynkWidgetWrite49, BlynkWidgetWrite50, BlynkWidgetWrite51,
BlynkWidgetWrite52, BlynkWidgetWrite53, BlynkWidgetWrite54, BlynkWidgetWrite55,
BlynkWidgetWrite56, BlynkWidgetWrite57, BlynkWidgetWrite58, BlynkWidgetWrite59,
BlynkWidgetWrite60, BlynkWidgetWrite61, BlynkWidgetWrite62, BlynkWidgetWrite63,
BlynkWidgetWrite64, BlynkWidgetWrite65, BlynkWidgetWrite66, BlynkWidgetWrite67,
BlynkWidgetWrite68, BlynkWidgetWrite69, BlynkWidgetWrite70, BlynkWidgetWrite71,
BlynkWidgetWrite72, BlynkWidgetWrite73, BlynkWidgetWrite74, BlynkWidgetWrite75,
BlynkWidgetWrite76, BlynkWidgetWrite77, BlynkWidgetWrite78, BlynkWidgetWrite79,
BlynkWidgetWrite80, BlynkWidgetWrite81, BlynkWidgetWrite82, BlynkWidgetWrite83,
BlynkWidgetWrite84, BlynkWidgetWrite85, BlynkWidgetWrite86, BlynkWidgetWrite87,
BlynkWidgetWrite88, BlynkWidgetWrite89, BlynkWidgetWrite90, BlynkWidgetWrite91,
BlynkWidgetWrite92, BlynkWidgetWrite93, BlynkWidgetWrite94, BlynkWidgetWrite95,
BlynkWidgetWrite96, BlynkWidgetWrite97, BlynkWidgetWrite98, BlynkWidgetWrite99,
BlynkWidgetWrite100, BlynkWidgetWrite101, BlynkWidgetWrite102, BlynkWidgetWrite103,
BlynkWidgetWrite104, BlynkWidgetWrite105, BlynkWidgetWrite106, BlynkWidgetWrite107,
BlynkWidgetWrite108, BlynkWidgetWrite109, BlynkWidgetWrite110, BlynkWidgetWrite111,
BlynkWidgetWrite112, BlynkWidgetWrite113, BlynkWidgetWrite114, BlynkWidgetWrite115,
BlynkWidgetWrite116, BlynkWidgetWrite117, BlynkWidgetWrite118, BlynkWidgetWrite119,
BlynkWidgetWrite120, BlynkWidgetWrite121, BlynkWidgetWrite122, BlynkWidgetWrite123,
BlynkWidgetWrite124, BlynkWidgetWrite125, BlynkWidgetWrite126, BlynkWidgetWrite127,
#endif
};
WidgetReadHandler GetReadHandler(uint8_t pin)
{
if (pin >= BLYNK_COUNT_OF(BlynkReadHandlerVector))
return NULL;
#ifdef BLYNK_HAS_PROGMEM
return (WidgetReadHandler)pgm_read_word(&BlynkReadHandlerVector[pin]);
#else
return BlynkReadHandlerVector[pin];
#endif
}
WidgetWriteHandler GetWriteHandler(uint8_t pin)
{
if (pin >= BLYNK_COUNT_OF(BlynkWriteHandlerVector))
return NULL;
#ifdef BLYNK_HAS_PROGMEM
return (WidgetWriteHandler)pgm_read_word(&BlynkWriteHandlerVector[pin]);
#else
return BlynkWriteHandlerVector[pin];
#endif
}

View File

@@ -0,0 +1,511 @@
/**
* @file BlynkHandlers.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Jan 2015
* @brief Handlers for virtual pin operations
*
*/
#ifndef BlynkHandlers_h
#define BlynkHandlers_h
#include "BlynkConfig.h"
#include "BlynkParam.h"
// Helper macro
#define V0 0
#define V1 1
#define V2 2
#define V3 3
#define V4 4
#define V5 5
#define V6 6
#define V7 7
#define V8 8
#define V9 9
#define V10 10
#define V11 11
#define V12 12
#define V13 13
#define V14 14
#define V15 15
#define V16 16
#define V17 17
#define V18 18
#define V19 19
#define V20 20
#define V21 21
#define V22 22
#define V23 23
#define V24 24
#define V25 25
#define V26 26
#define V27 27
#define V28 28
#define V29 29
#define V30 30
#define V31 31
#ifdef BLYNK_USE_128_VPINS
#define V32 32
#define V33 33
#define V34 34
#define V35 35
#define V36 36
#define V37 37
#define V38 38
#define V39 39
#define V40 40
#define V41 41
#define V42 42
#define V43 43
#define V44 44
#define V45 45
#define V46 46
#define V47 47
#define V48 48
#define V49 49
#define V50 50
#define V51 51
#define V52 52
#define V53 53
#define V54 54
#define V55 55
#define V56 56
#define V57 57
#define V58 58
#define V59 59
#define V60 60
#define V61 61
#define V62 62
#define V63 63
#define V64 64
#define V65 65
#define V66 66
#define V67 67
#define V68 68
#define V69 69
#define V70 70
#define V71 71
#define V72 72
#define V73 73
#define V74 74
#define V75 75
#define V76 76
#define V77 77
#define V78 78
#define V79 79
#define V80 80
#define V81 81
#define V82 82
#define V83 83
#define V84 84
#define V85 85
#define V86 86
#define V87 87
#define V88 88
#define V89 89
#define V90 90
#define V91 91
#define V92 92
#define V93 93
#define V94 94
#define V95 95
#define V96 96
#define V97 97
#define V98 98
#define V99 99
#define V100 100
#define V101 101
#define V102 102
#define V103 103
#define V104 104
#define V105 105
#define V106 106
#define V107 107
#define V108 108
#define V109 109
#define V110 110
#define V111 111
#define V112 112
#define V113 113
#define V114 114
#define V115 115
#define V116 116
#define V117 117
#define V118 118
#define V119 119
#define V120 120
#define V121 121
#define V122 122
#define V123 123
#define V124 124
#define V125 125
#define V126 126
#define V127 127
#endif
// Initial syntax:
#define BLYNK_WRITE_2(pin) \
void BlynkWidgetWrite ## pin (BlynkReq BLYNK_UNUSED &request, const BlynkParam BLYNK_UNUSED &param)
#define BLYNK_READ_2(pin) \
void BlynkWidgetRead ## pin (BlynkReq BLYNK_UNUSED &request)
#define BLYNK_WRITE_DEFAULT() BLYNK_WRITE_2(Default)
#define BLYNK_READ_DEFAULT() BLYNK_READ_2(Default)
#define BLYNK_WRITE(pin) BLYNK_WRITE_2(pin)
#define BLYNK_READ(pin) BLYNK_READ_2(pin)
// New, more readable syntax:
#define BLYNK_IN_2(pin) \
void BlynkWidgetWrite ## pin (BlynkReq BLYNK_UNUSED &request, const BlynkParam BLYNK_UNUSED &getValue)
#define BLYNK_OUT_2(pin) \
void BlynkWidgetRead ## pin (BlynkReq BLYNK_UNUSED &request)
#define BLYNK_INPUT_DEFAULT() BLYNK_IN_2(Default)
#define BLYNK_OUTPUT_DEFAULT() BLYNK_OUT_2(Default)
#define BLYNK_INPUT(pin) BLYNK_IN_2(pin)
#define BLYNK_OUTPUT(pin) BLYNK_OUT_2(pin)
// Additional handlers
#define BLYNK_CONNECTED() void BlynkOnConnected()
#define BLYNK_DISCONNECTED() void BlynkOnDisconnected()
// Advanced functions
#define BLYNK_VAR_INT(name, pin) \
int name; \
BLYNK_WRITE(pin) { name = param.asInt(); } \
BLYNK_READ(pin) { Blynk.virtualWrite(pin, name); }
#define BLYNK_VAR_LONG(name, pin) \
long name; \
BLYNK_WRITE(pin) { name = param.asLong(); } \
BLYNK_READ(pin) { Blynk.virtualWrite(pin, name); }
#ifndef BLYNK_NO_FLOAT
#define BLYNK_VAR_DOUBLE(name, pin) \
double name; \
BLYNK_WRITE(pin) { name = param.asDouble(); } \
BLYNK_READ(pin) { Blynk.virtualWrite(pin, name); }
#endif
#ifdef ARDUINO
#define BLYNK_VAR_STRING(name, pin) \
String name; \
BLYNK_WRITE(pin) { name = param.asStr(); } \
BLYNK_READ(pin) { Blynk.virtualWrite(pin, name); }
#endif
// Default read/write handlers (you can redefine them in your code)
#ifdef __cplusplus
extern "C" {
#endif
struct BlynkReq
{
uint8_t pin;
};
typedef void (*WidgetReadHandler)(BlynkReq BLYNK_UNUSED &request);
typedef void (*WidgetWriteHandler)(BlynkReq BLYNK_UNUSED &request, const BlynkParam BLYNK_UNUSED &param);
WidgetReadHandler GetReadHandler(uint8_t pin);
WidgetWriteHandler GetWriteHandler(uint8_t pin);
// Declare placeholders
BLYNK_READ();
BLYNK_WRITE();
void BlynkNoOpCbk();
// Declare all pin handlers (you can redefine them in your code)
BLYNK_CONNECTED();
BLYNK_DISCONNECTED();
// Internal Virtual Pins
BLYNK_WRITE(InternalPinACON);
BLYNK_WRITE(InternalPinADIS);
BLYNK_WRITE(InternalPinRTC);
BLYNK_WRITE(InternalPinOTA);
// Aliases
#define BLYNK_APP_CONNECTED() BLYNK_WRITE(InternalPinACON)
#define BLYNK_APP_DISCONNECTED() BLYNK_WRITE(InternalPinADIS)
// Regular Virtual Pins
BLYNK_READ_DEFAULT();
BLYNK_WRITE_DEFAULT();
BLYNK_READ(0 );
BLYNK_READ(1 );
BLYNK_READ(2 );
BLYNK_READ(3 );
BLYNK_READ(4 );
BLYNK_READ(5 );
BLYNK_READ(6 );
BLYNK_READ(7 );
BLYNK_READ(8 );
BLYNK_READ(9 );
BLYNK_READ(10);
BLYNK_READ(11);
BLYNK_READ(12);
BLYNK_READ(13);
BLYNK_READ(14);
BLYNK_READ(15);
BLYNK_READ(16);
BLYNK_READ(17);
BLYNK_READ(18);
BLYNK_READ(19);
BLYNK_READ(20);
BLYNK_READ(21);
BLYNK_READ(22);
BLYNK_READ(23);
BLYNK_READ(24);
BLYNK_READ(25);
BLYNK_READ(26);
BLYNK_READ(27);
BLYNK_READ(28);
BLYNK_READ(29);
BLYNK_READ(30);
BLYNK_READ(31);
#ifdef BLYNK_USE_128_VPINS
BLYNK_READ(32);
BLYNK_READ(33);
BLYNK_READ(34);
BLYNK_READ(35);
BLYNK_READ(36);
BLYNK_READ(37);
BLYNK_READ(38);
BLYNK_READ(39);
BLYNK_READ(40);
BLYNK_READ(41);
BLYNK_READ(42);
BLYNK_READ(43);
BLYNK_READ(44);
BLYNK_READ(45);
BLYNK_READ(46);
BLYNK_READ(47);
BLYNK_READ(48);
BLYNK_READ(49);
BLYNK_READ(50);
BLYNK_READ(51);
BLYNK_READ(52);
BLYNK_READ(53);
BLYNK_READ(54);
BLYNK_READ(55);
BLYNK_READ(56);
BLYNK_READ(57);
BLYNK_READ(58);
BLYNK_READ(59);
BLYNK_READ(60);
BLYNK_READ(61);
BLYNK_READ(62);
BLYNK_READ(63);
BLYNK_READ(64);
BLYNK_READ(65);
BLYNK_READ(66);
BLYNK_READ(67);
BLYNK_READ(68);
BLYNK_READ(69);
BLYNK_READ(70);
BLYNK_READ(71);
BLYNK_READ(72);
BLYNK_READ(73);
BLYNK_READ(74);
BLYNK_READ(75);
BLYNK_READ(76);
BLYNK_READ(77);
BLYNK_READ(78);
BLYNK_READ(79);
BLYNK_READ(80);
BLYNK_READ(81);
BLYNK_READ(82);
BLYNK_READ(83);
BLYNK_READ(84);
BLYNK_READ(85);
BLYNK_READ(86);
BLYNK_READ(87);
BLYNK_READ(88);
BLYNK_READ(89);
BLYNK_READ(90);
BLYNK_READ(91);
BLYNK_READ(92);
BLYNK_READ(93);
BLYNK_READ(94);
BLYNK_READ(95);
BLYNK_READ(96);
BLYNK_READ(97);
BLYNK_READ(98);
BLYNK_READ(99);
BLYNK_READ(100);
BLYNK_READ(101);
BLYNK_READ(102);
BLYNK_READ(103);
BLYNK_READ(104);
BLYNK_READ(105);
BLYNK_READ(106);
BLYNK_READ(107);
BLYNK_READ(108);
BLYNK_READ(109);
BLYNK_READ(110);
BLYNK_READ(111);
BLYNK_READ(112);
BLYNK_READ(113);
BLYNK_READ(114);
BLYNK_READ(115);
BLYNK_READ(116);
BLYNK_READ(117);
BLYNK_READ(118);
BLYNK_READ(119);
BLYNK_READ(120);
BLYNK_READ(121);
BLYNK_READ(122);
BLYNK_READ(123);
BLYNK_READ(124);
BLYNK_READ(125);
BLYNK_READ(126);
BLYNK_READ(127);
#endif
BLYNK_WRITE(0 );
BLYNK_WRITE(1 );
BLYNK_WRITE(2 );
BLYNK_WRITE(3 );
BLYNK_WRITE(4 );
BLYNK_WRITE(5 );
BLYNK_WRITE(6 );
BLYNK_WRITE(7 );
BLYNK_WRITE(8 );
BLYNK_WRITE(9 );
BLYNK_WRITE(10);
BLYNK_WRITE(11);
BLYNK_WRITE(12);
BLYNK_WRITE(13);
BLYNK_WRITE(14);
BLYNK_WRITE(15);
BLYNK_WRITE(16);
BLYNK_WRITE(17);
BLYNK_WRITE(18);
BLYNK_WRITE(19);
BLYNK_WRITE(20);
BLYNK_WRITE(21);
BLYNK_WRITE(22);
BLYNK_WRITE(23);
BLYNK_WRITE(24);
BLYNK_WRITE(25);
BLYNK_WRITE(26);
BLYNK_WRITE(27);
BLYNK_WRITE(28);
BLYNK_WRITE(29);
BLYNK_WRITE(30);
BLYNK_WRITE(31);
#ifdef BLYNK_USE_128_VPINS
BLYNK_WRITE(32);
BLYNK_WRITE(33);
BLYNK_WRITE(34);
BLYNK_WRITE(35);
BLYNK_WRITE(36);
BLYNK_WRITE(37);
BLYNK_WRITE(38);
BLYNK_WRITE(39);
BLYNK_WRITE(40);
BLYNK_WRITE(41);
BLYNK_WRITE(42);
BLYNK_WRITE(43);
BLYNK_WRITE(44);
BLYNK_WRITE(45);
BLYNK_WRITE(46);
BLYNK_WRITE(47);
BLYNK_WRITE(48);
BLYNK_WRITE(49);
BLYNK_WRITE(50);
BLYNK_WRITE(51);
BLYNK_WRITE(52);
BLYNK_WRITE(53);
BLYNK_WRITE(54);
BLYNK_WRITE(55);
BLYNK_WRITE(56);
BLYNK_WRITE(57);
BLYNK_WRITE(58);
BLYNK_WRITE(59);
BLYNK_WRITE(60);
BLYNK_WRITE(61);
BLYNK_WRITE(62);
BLYNK_WRITE(63);
BLYNK_WRITE(64);
BLYNK_WRITE(65);
BLYNK_WRITE(66);
BLYNK_WRITE(67);
BLYNK_WRITE(68);
BLYNK_WRITE(69);
BLYNK_WRITE(70);
BLYNK_WRITE(71);
BLYNK_WRITE(72);
BLYNK_WRITE(73);
BLYNK_WRITE(74);
BLYNK_WRITE(75);
BLYNK_WRITE(76);
BLYNK_WRITE(77);
BLYNK_WRITE(78);
BLYNK_WRITE(79);
BLYNK_WRITE(80);
BLYNK_WRITE(81);
BLYNK_WRITE(82);
BLYNK_WRITE(83);
BLYNK_WRITE(84);
BLYNK_WRITE(85);
BLYNK_WRITE(86);
BLYNK_WRITE(87);
BLYNK_WRITE(88);
BLYNK_WRITE(89);
BLYNK_WRITE(90);
BLYNK_WRITE(91);
BLYNK_WRITE(92);
BLYNK_WRITE(93);
BLYNK_WRITE(94);
BLYNK_WRITE(95);
BLYNK_WRITE(96);
BLYNK_WRITE(97);
BLYNK_WRITE(98);
BLYNK_WRITE(99);
BLYNK_WRITE(100);
BLYNK_WRITE(101);
BLYNK_WRITE(102);
BLYNK_WRITE(103);
BLYNK_WRITE(104);
BLYNK_WRITE(105);
BLYNK_WRITE(106);
BLYNK_WRITE(107);
BLYNK_WRITE(108);
BLYNK_WRITE(109);
BLYNK_WRITE(110);
BLYNK_WRITE(111);
BLYNK_WRITE(112);
BLYNK_WRITE(113);
BLYNK_WRITE(114);
BLYNK_WRITE(115);
BLYNK_WRITE(116);
BLYNK_WRITE(117);
BLYNK_WRITE(118);
BLYNK_WRITE(119);
BLYNK_WRITE(120);
BLYNK_WRITE(121);
BLYNK_WRITE(122);
BLYNK_WRITE(123);
BLYNK_WRITE(124);
BLYNK_WRITE(125);
BLYNK_WRITE(126);
BLYNK_WRITE(127);
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,379 @@
/**
* @file BlynkParam.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Jan 2015
* @brief Container for handler parameters
*
*/
#ifndef BlynkParam_h
#define BlynkParam_h
#include <string.h>
#include <stdlib.h>
#include "BlynkConfig.h"
#include "BlynkDebug.h"
#define BLYNK_PARAM_KV(k, v) k "\0" v "\0"
class BlynkParam
{
public:
class iterator
{
public:
iterator(const char* c, const char* l) : ptr(c), limit(l) {}
static iterator invalid() { return iterator(NULL, NULL); }
operator const char* () const { return asStr(); }
operator int () const { return asInt(); }
const char* asStr() const { return ptr; }
const char* asString() const { return ptr; }
int asInt() const { if(!isValid()) return 0; return atoi(ptr); }
long asLong() const { if(!isValid()) return 0; return atol(ptr); }
//long long asLongLong() const { return atoll(ptr); }
#ifndef BLYNK_NO_FLOAT
double asDouble() const { if(!isValid()) return 0; return atof(ptr); }
float asFloat() const { if(!isValid()) return 0; return atof(ptr); }
#endif
bool isValid() const { return ptr != NULL && ptr < limit; }
bool isEmpty() const { if(!isValid()) return true; return *ptr == '\0'; }
bool operator < (const iterator& it) const { return ptr < it.ptr; }
bool operator >= (const iterator& it) const { return ptr >= it.ptr; }
iterator& operator ++() {
if(isValid()) {
ptr += strlen(ptr) + 1;
}
return *this;
}
private:
const char* ptr;
const char* limit;
};
public:
explicit
BlynkParam(void* addr, size_t length)
: buff((char*)addr), len(length), buff_size(length)
{}
explicit
BlynkParam(void* addr, size_t length, size_t buffsize)
: buff((char*)addr), len(length), buff_size(buffsize)
{}
const char* asStr() const { return buff; }
const char* asString() const { return buff; }
int asInt() const { return atoi(buff); }
long asLong() const { return atol(buff); }
//long long asLongLong() const { return atoll(buff); }
#ifndef BLYNK_NO_FLOAT
double asDouble() const { return atof(buff); }
float asFloat() const { return atof(buff); }
#endif
bool isEmpty() const { return *buff == '\0'; }
iterator begin() const { return iterator(buff, buff+len); }
iterator end() const { return iterator(buff+len, buff+len); }
iterator operator[](int index) const;
iterator operator[](const char* key) const;
void* getBuffer() const { return (void*)buff; }
size_t getLength() const { return len; }
// Modification
void add(int value);
void add(unsigned int value);
void add(long value);
void add(unsigned long value);
void add(long long value);
void add(unsigned long long value);
#ifndef BLYNK_NO_FLOAT
void add(float value);
void add(double value);
#endif
void add(const char* str);
void add(const void* b, size_t l);
#if defined(ARDUINO) || defined(SPARK) || defined(PARTICLE)
void add(const String& str);
#if defined(BLYNK_HAS_PROGMEM)
void add(const __FlashStringHelper* str);
#endif
#endif
template<typename T, typename... Args>
void add_multi(T last) {
add(last);
}
template<typename T, typename... Args>
void add_multi(T head, Args... tail) {
add(head);
add_multi(tail...);
}
template <typename TV>
void add_key(const char* key, const TV& val) {
add(key);
add(val);
}
protected:
char* buff;
size_t len;
size_t buff_size;
};
class BlynkParamAllocated
: public BlynkParam
{
public:
BlynkParamAllocated(size_t size)
: BlynkParam(malloc(size), 0, size)
{}
~BlynkParamAllocated() {
free(buff);
}
};
inline
BlynkParam::iterator BlynkParam::operator[](int index) const
{
const iterator e = end();
for (iterator it = begin(); it < e; ++it) {
if (!index--) {
return it;
}
}
return iterator::invalid();
}
inline
BlynkParam::iterator BlynkParam::operator[](const char* key) const
{
const iterator e = end();
for (iterator it = begin(); it < e; ++it) {
if (!strcmp(it.asStr(), key)) {
return ++it;
}
++it;
if (it >= e) break;
}
return iterator::invalid();
}
inline
void BlynkParam::add(const void* b, size_t l)
{
if (len + l > buff_size)
return;
memcpy(buff+len, b, l);
len += l;
}
inline
void BlynkParam::add(const char* str)
{
if (str == NULL) {
buff[len++] = '\0';
return;
}
add(str, strlen(str)+1);
}
#if defined(ARDUINO) || defined(SPARK) || defined(PARTICLE)
inline
void BlynkParam::add(const String& str)
{
#if defined(ARDUINO_AVR_DIGISPARK) \
|| defined(__ARDUINO_X86__) \
|| defined(__RFduino__)
size_t len = str.length()+1;
char buff[len];
const_cast<String&>(str).toCharArray(buff, len);
add(buff, len);
#else
add(str.c_str());
#endif
}
#if defined(BLYNK_HAS_PROGMEM)
inline
void BlynkParam::add(const __FlashStringHelper* ifsh)
{
PGM_P p = reinterpret_cast<PGM_P>(ifsh);
size_t l = strlen_P(p) + 1;
if (len + l > buff_size)
return;
memcpy_P(buff+len, p, l);
len += l;
buff[len] = '\0';
}
#endif
#endif
#if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
#include <stdlib.h>
inline
void BlynkParam::add(int value)
{
char str[2 + 8 * sizeof(value)];
itoa(value, str, 10);
add(str);
}
inline
void BlynkParam::add(unsigned int value)
{
char str[1 + 8 * sizeof(value)];
utoa(value, str, 10);
add(str);
}
inline
void BlynkParam::add(long value)
{
char str[2 + 8 * sizeof(value)];
ltoa(value, str, 10);
add(str);
}
inline
void BlynkParam::add(unsigned long value)
{
char str[1 + 8 * sizeof(value)];
ultoa(value, str, 10);
add(str);
}
inline
void BlynkParam::add(long long value) // TODO: this currently adds just a long
{
char str[2 + 8 * sizeof(value)];
ltoa(value, str, 10);
add(str);
}
inline
void BlynkParam::add(unsigned long long value) // TODO: this currently adds just a long
{
char str[1 + 8 * sizeof(value)];
ultoa(value, str, 10);
add(str);
}
#ifndef BLYNK_NO_FLOAT
inline
void BlynkParam::add(float value)
{
char str[33];
dtostrf(value, 5, 3, str);
add(str);
}
inline
void BlynkParam::add(double value)
{
char str[33];
dtostrf(value, 5, 7, str);
add(str);
}
#endif
#else
#include <stdio.h>
inline
void BlynkParam::add(int value)
{
len += snprintf(buff+len, buff_size-len, "%i", value)+1;
}
inline
void BlynkParam::add(unsigned int value)
{
len += snprintf(buff+len, buff_size-len, "%u", value)+1;
}
inline
void BlynkParam::add(long value)
{
len += snprintf(buff+len, buff_size-len, "%li", value)+1;
}
inline
void BlynkParam::add(unsigned long value)
{
len += snprintf(buff+len, buff_size-len, "%lu", value)+1;
}
inline
void BlynkParam::add(long long value)
{
len += snprintf(buff+len, buff_size-len, "%lli", value)+1;
}
inline
void BlynkParam::add(unsigned long long value)
{
len += snprintf(buff+len, buff_size-len, "%llu", value)+1;
}
#ifndef BLYNK_NO_FLOAT
#if defined(BLYNK_USE_INTERNAL_DTOSTRF)
extern char* dtostrf_internal(double number, signed char width, unsigned char prec, char *s);
inline
void BlynkParam::add(float value)
{
char str[33];
dtostrf_internal(value, 5, 3, str);
add(str);
}
inline
void BlynkParam::add(double value)
{
char str[33];
dtostrf_internal(value, 5, 7, str);
add(str);
}
#else
inline
void BlynkParam::add(float value)
{
len += snprintf(buff+len, buff_size-len, "%2.3f", value)+1;
}
inline
void BlynkParam::add(double value)
{
len += snprintf(buff+len, buff_size-len, "%2.7f", value)+1;
}
#endif
#endif
#endif
#endif

View File

@@ -0,0 +1,535 @@
/**
* @file BlynkProtocol.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Jan 2015
* @brief Blynk protocol implementation
*
*/
#ifndef BlynkProtocol_h
#define BlynkProtocol_h
#include <string.h>
#include <stdlib.h>
#include "BlynkDebug.h"
#include "BlynkProtocolDefs.h"
#include "BlynkApi.h"
#include "BlynkUtility.h"
template <class Transp>
class BlynkProtocol
: public BlynkApi< BlynkProtocol<Transp> >
{
friend class BlynkApi< BlynkProtocol<Transp> >;
public:
enum BlynkState {
CONNECTING,
CONNECTED,
DISCONNECTED,
};
BlynkProtocol(Transp& transp)
: conn(transp)
, authkey(NULL)
, redir_serv(NULL)
, lastActivityIn(0)
, lastActivityOut(0)
, lastHeartbeat(0)
, msgIdOut(0)
, msgIdOutOverride(0)
, nesting(0)
, state(CONNECTING)
{}
bool connected() { return state == CONNECTED; }
bool connect(uint32_t timeout = BLYNK_TIMEOUT_MS*3) {
conn.disconnect();
state = CONNECTING;
millis_time_t started = BlynkMillis();
while ((state != CONNECTED) &&
(BlynkMillis() - started < timeout))
{
run();
}
return state == CONNECTED;
}
void disconnect() {
conn.disconnect();
state = DISCONNECTED;
BLYNK_LOG1(BLYNK_F("Disconnected"));
}
bool run(bool avail = false);
// TODO: Fixme
void startSession() {
conn.connect();
state = CONNECTING;
msgIdOut = 0;
lastHeartbeat = lastActivityIn = lastActivityOut = (BlynkMillis() - 5000UL);
}
void sendCmd(uint8_t cmd, uint16_t id = 0, const void* data = NULL, size_t length = 0, const void* data2 = NULL, size_t length2 = 0);
private:
void internalReconnect() {
state = CONNECTING;
conn.disconnect();
BlynkOnDisconnected();
}
int readHeader(BlynkHeader& hdr);
uint16_t getNextMsgId();
protected:
void begin(const char* auth) {
this->authkey = auth;
lastHeartbeat = lastActivityIn = lastActivityOut = (BlynkMillis() - 5000UL);
#if defined(BLYNK_NO_FANCY_LOGO)
BLYNK_LOG1(BLYNK_F("Blynk v" BLYNK_VERSION " on " BLYNK_INFO_DEVICE));
#else
BLYNK_LOG1(BLYNK_F(BLYNK_NEWLINE
" ___ __ __" BLYNK_NEWLINE
" / _ )/ /_ _____ / /__" BLYNK_NEWLINE
" / _ / / // / _ \\/ '_/" BLYNK_NEWLINE
" /____/_/\\_, /_//_/_/\\_\\" BLYNK_NEWLINE
" /___/ v" BLYNK_VERSION " on " BLYNK_INFO_DEVICE BLYNK_NEWLINE
BLYNK_NEWLINE
" Give Blynk a Github star! => https://github.com/blynkkk/blynk-library" BLYNK_NEWLINE
));
#endif
}
bool processInput(void);
Transp& conn;
private:
const char* authkey;
char* redir_serv;
millis_time_t lastActivityIn;
millis_time_t lastActivityOut;
union {
millis_time_t lastHeartbeat;
millis_time_t lastLogin;
};
uint16_t msgIdOut;
uint16_t msgIdOutOverride;
uint8_t nesting;
protected:
BlynkState state;
};
template <class Transp>
bool BlynkProtocol<Transp>::run(bool avail)
{
BLYNK_RUN_YIELD();
if (state == DISCONNECTED) {
return false;
}
// Detect nesting
BlynkHelperAutoInc guard(nesting);
if (msgIdOutOverride || nesting > 2) {
//BLYNK_LOG1(BLYNK_F("Nested run() skipped"));
return true;
}
if (conn.connected()) {
while (avail || conn.available() > 0) {
//BLYNK_LOG2(BLYNK_F("Available: "), conn.available());
//const unsigned long t = micros();
if (!processInput()) {
conn.disconnect();
// TODO: Only when in direct mode?
#ifdef BLYNK_USE_DIRECT_CONNECT
state = CONNECTING;
#endif
BlynkOnDisconnected();
return false;
}
avail = false;
//BLYNK_LOG2(BLYNK_F("Proc time: "), micros() - t);
}
}
const millis_time_t t = BlynkMillis();
// Update connection status after running commands
const bool tconn = conn.connected();
if (state == CONNECTED) {
if (!tconn) {
lastHeartbeat = t;
internalReconnect();
return false;
}
if (t - lastActivityIn > (1000UL * BLYNK_HEARTBEAT + BLYNK_TIMEOUT_MS*3)) {
#ifdef BLYNK_DEBUG
BLYNK_LOG6(BLYNK_F("Heartbeat timeout: "), t, BLYNK_F(", "), lastActivityIn, BLYNK_F(", "), lastHeartbeat);
#else
BLYNK_LOG1(BLYNK_F("Heartbeat timeout"));
#endif
internalReconnect();
return false;
} else if ((t - lastActivityIn > 1000UL * BLYNK_HEARTBEAT ||
t - lastActivityOut > 1000UL * BLYNK_HEARTBEAT) &&
t - lastHeartbeat > BLYNK_TIMEOUT_MS)
{
// Send ping if we didn't either send or receive something
// for BLYNK_HEARTBEAT seconds
sendCmd(BLYNK_CMD_PING);
lastHeartbeat = t;
}
} else if (state == CONNECTING) {
#ifdef BLYNK_USE_DIRECT_CONNECT
if (!tconn)
conn.connect();
#else
if (tconn && (t - lastLogin > BLYNK_TIMEOUT_MS)) {
BLYNK_LOG1(BLYNK_F("Login timeout"));
conn.disconnect();
state = CONNECTING;
return false;
} else if (!tconn && (t - lastLogin > 5000UL)) {
conn.disconnect();
if (!conn.connect()) {
lastLogin = t;
return false;
}
msgIdOut = 1;
sendCmd(BLYNK_CMD_LOGIN, 1, authkey, strlen(authkey));
lastLogin = lastActivityOut;
return true;
}
#endif
}
return true;
}
template <class Transp>
BLYNK_FORCE_INLINE
bool BlynkProtocol<Transp>::processInput(void)
{
BlynkHeader hdr;
const int ret = readHeader(hdr);
if (ret == 0) {
return true; // Considered OK (no data on input)
}
if (ret < 0 || hdr.msg_id == 0) {
#ifdef BLYNK_DEBUG
BLYNK_LOG2(BLYNK_F("Bad hdr len: "), ret);
#endif
return false;
}
if (hdr.type == BLYNK_CMD_RESPONSE) {
lastActivityIn = BlynkMillis();
#ifndef BLYNK_USE_DIRECT_CONNECT
if (state == CONNECTING && (1 == hdr.msg_id)) {
switch (hdr.length) {
case BLYNK_SUCCESS:
case BLYNK_ALREADY_REGISTERED:
BLYNK_LOG3(BLYNK_F("Ready (ping: "), lastActivityIn-lastHeartbeat, BLYNK_F("ms)."));
lastHeartbeat = lastActivityIn;
state = CONNECTED;
#ifdef BLYNK_DEBUG
if (size_t ram = BlynkFreeRam()) {
BLYNK_LOG2(BLYNK_F("Free RAM: "), ram);
}
#endif
this->sendInfo();
BLYNK_RUN_YIELD();
BlynkOnConnected();
return true;
case BLYNK_INVALID_TOKEN:
BLYNK_LOG1(BLYNK_F("Invalid auth token"));
break;
default:
BLYNK_LOG2(BLYNK_F("Connect failed. code: "), hdr.length);
}
return false;
}
if (BLYNK_NOT_AUTHENTICATED == hdr.length) {
return false;
}
#endif
// TODO: return code may indicate App presence
return true;
}
if (hdr.length > BLYNK_MAX_READBYTES) {
BLYNK_LOG2(BLYNK_F("Packet too big: "), hdr.length);
// TODO: Flush
internalReconnect();
return true;
}
uint8_t inputBuffer[hdr.length+1]; // Add 1 to zero-terminate
if (hdr.length != conn.read(inputBuffer, hdr.length)) {
#ifdef BLYNK_DEBUG
BLYNK_LOG1(BLYNK_F("Can't read body"));
#endif
return false;
}
inputBuffer[hdr.length] = '\0';
BLYNK_DBG_DUMP(">", inputBuffer, hdr.length);
lastActivityIn = BlynkMillis();
switch (hdr.type)
{
case BLYNK_CMD_LOGIN: {
#ifdef BLYNK_USE_DIRECT_CONNECT
if (strncmp(authkey, (char*)inputBuffer, 32)) {
BLYNK_LOG1(BLYNK_F("Invalid token"));
sendCmd(BLYNK_CMD_RESPONSE, hdr.msg_id, NULL, BLYNK_INVALID_TOKEN);
break;
}
#endif
if (state == CONNECTING) {
BLYNK_LOG1(BLYNK_F("Ready"));
state = CONNECTED;
#ifdef BLYNK_DEBUG
if (size_t ram = BlynkFreeRam()) {
BLYNK_LOG2(BLYNK_F("Free RAM: "), ram);
}
#endif
this->sendInfo();
BLYNK_RUN_YIELD();
BlynkOnConnected();
}
sendCmd(BLYNK_CMD_RESPONSE, hdr.msg_id, NULL, BLYNK_SUCCESS);
} break;
case BLYNK_CMD_PING: {
sendCmd(BLYNK_CMD_RESPONSE, hdr.msg_id, NULL, BLYNK_SUCCESS);
} break;
case BLYNK_CMD_REDIRECT: {
if (!redir_serv) {
redir_serv = (char*)malloc(32);
}
BlynkParam param(inputBuffer, hdr.length);
uint16_t redir_port = BLYNK_DEFAULT_PORT; // TODO: Fixit
BlynkParam::iterator it = param.begin();
if (it >= param.end())
return false;
strncpy(redir_serv, it.asStr(), 32);
if (++it < param.end())
redir_port = it.asLong();
BLYNK_LOG4(BLYNK_F("Redirecting to "), redir_serv, ':', redir_port);
conn.disconnect();
conn.begin(redir_serv, redir_port);
state = CONNECTING;
lastHeartbeat = lastActivityIn = lastActivityOut = (BlynkMillis() - 5000UL);
} break;
case BLYNK_CMD_HARDWARE:
case BLYNK_CMD_BRIDGE: {
msgIdOutOverride = hdr.msg_id;
this->processCmd(inputBuffer, hdr.length);
msgIdOutOverride = 0;
} break;
case BLYNK_CMD_INTERNAL: {
BlynkReq req = { 0 };
BlynkParam param(inputBuffer, hdr.length);
BlynkParam::iterator it = param.begin();
if (it >= param.end())
return true;
uint32_t cmd32;
memcpy(&cmd32, it.asStr(), sizeof(cmd32));
++it;
char* start = (char*)(it).asStr();
unsigned length = hdr.length - (start - (char*)inputBuffer);
BlynkParam param2(start, length);
switch (cmd32) {
case BLYNK_INT_RTC: BlynkWidgetWriteInternalPinRTC(req, param2); break;
case BLYNK_INT_OTA: BlynkWidgetWriteInternalPinOTA(req, param2); break;
case BLYNK_INT_ACON: BlynkWidgetWriteInternalPinACON(req, param2); break;
case BLYNK_INT_ADIS: BlynkWidgetWriteInternalPinADIS(req, param2); break;
#ifdef BLYNK_DEBUG
default: BLYNK_LOG2(BLYNK_F("Invalid internal cmd:"), param.asStr());
#endif
}
} break;
case BLYNK_CMD_DEBUG_PRINT: {
if (hdr.length) {
BLYNK_LOG2(BLYNK_F("Server: "), (char*)inputBuffer);
}
} break;
default: {
#ifdef BLYNK_DEBUG
BLYNK_LOG2(BLYNK_F("Invalid header type: "), hdr.type);
#endif
// TODO: Flush
internalReconnect();
} break;
}
return true;
}
template <class Transp>
int BlynkProtocol<Transp>::readHeader(BlynkHeader& hdr)
{
size_t rlen = conn.read(&hdr, sizeof(hdr));
if (rlen == 0) {
return 0;
}
if (sizeof(hdr) != rlen) {
return -1;
}
BLYNK_DBG_DUMP(">", &hdr, sizeof(BlynkHeader));
hdr.msg_id = ntohs(hdr.msg_id);
hdr.length = ntohs(hdr.length);
return rlen;
}
#ifndef BLYNK_SEND_THROTTLE
#define BLYNK_SEND_THROTTLE 0
#endif
#ifndef BLYNK_SEND_CHUNK
#define BLYNK_SEND_CHUNK 1024 // Just a big number
#endif
template <class Transp>
void BlynkProtocol<Transp>::sendCmd(uint8_t cmd, uint16_t id, const void* data, size_t length, const void* data2, size_t length2)
{
if (!conn.connected() || (cmd != BLYNK_CMD_RESPONSE && cmd != BLYNK_CMD_PING && cmd != BLYNK_CMD_LOGIN && state != CONNECTED) ) {
#ifdef BLYNK_DEBUG_ALL
BLYNK_LOG2(BLYNK_F("Cmd skipped:"), cmd);
#endif
return;
}
if (0 == id) {
id = getNextMsgId();
}
#if defined(BLYNK_MSG_LIMIT) && BLYNK_MSG_LIMIT > 0
if (cmd >= BLYNK_CMD_TWEET && cmd <= BLYNK_CMD_HARDWARE) {
const millis_time_t allowed_time = BlynkMax(lastActivityOut, lastActivityIn) + 1000/BLYNK_MSG_LIMIT;
int32_t wait_time = allowed_time - BlynkMillis();
if (wait_time >= 0) {
#ifdef BLYNK_DEBUG_ALL
BLYNK_LOG2(BLYNK_F("Waiting:"), wait_time);
#endif
while (wait_time >= 0) {
run();
wait_time = allowed_time - BlynkMillis();
}
} else if (nesting == 0) {
run();
}
}
#endif
const size_t full_length = (sizeof(BlynkHeader)) +
(data ? length : 0) +
(data2 ? length2 : 0);
#if defined(BLYNK_SEND_ATOMIC) || defined(ESP8266) || defined(ESP32) || defined(SPARK) || defined(PARTICLE) || defined(ENERGIA)
// Those have more RAM and like single write at a time...
uint8_t buff[full_length];
BlynkHeader* hdr = (BlynkHeader*)buff;
hdr->type = cmd;
hdr->msg_id = htons(id);
hdr->length = htons(length+length2);
size_t pos = sizeof(BlynkHeader);
if (data && length) {
memcpy(buff + pos, data, length);
pos += length;
}
if (data2 && length2) {
memcpy(buff + pos, data2, length2);
}
size_t wlen = 0;
while (wlen < full_length) {
const size_t chunk = BlynkMin(size_t(BLYNK_SEND_CHUNK), full_length - wlen);
BLYNK_DBG_DUMP("<", buff + wlen, chunk);
const size_t w = conn.write(buff + wlen, chunk);
BlynkDelay(BLYNK_SEND_THROTTLE);
if (w == 0) {
#ifdef BLYNK_DEBUG
BLYNK_LOG1(BLYNK_F("Cmd error"));
#endif
conn.disconnect();
state = CONNECTING;
BlynkOnDisconnected();
return;
}
wlen += w;
}
#else
BlynkHeader hdr;
hdr.type = cmd;
hdr.msg_id = htons(id);
hdr.length = htons(length+length2);
BLYNK_DBG_DUMP("<", &hdr, sizeof(hdr));
size_t wlen = conn.write(&hdr, sizeof(hdr));
BlynkDelay(BLYNK_SEND_THROTTLE);
if (cmd != BLYNK_CMD_RESPONSE) {
if (length) {
BLYNK_DBG_DUMP("<", data, length);
wlen += conn.write(data, length);
BlynkDelay(BLYNK_SEND_THROTTLE);
}
if (length2) {
BLYNK_DBG_DUMP("<", data2, length2);
wlen += conn.write(data2, length2);
BlynkDelay(BLYNK_SEND_THROTTLE);
}
}
#endif
if (wlen != full_length) {
#ifdef BLYNK_DEBUG
BLYNK_LOG4(BLYNK_F("Sent "), wlen, '/', full_length);
#endif
internalReconnect();
return;
}
lastActivityOut = BlynkMillis();
}
template <class Transp>
uint16_t BlynkProtocol<Transp>::getNextMsgId()
{
if (msgIdOutOverride != 0)
return msgIdOutOverride;
if (++msgIdOut == 0)
msgIdOut = 1;
return msgIdOut;
}
#endif

View File

@@ -0,0 +1,138 @@
/**
* @file BlynkProtocolDefs.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Jan 2015
* @brief Blynk protocol definitions
*
*/
#ifndef BlynkProtocolDefs_h
#define BlynkProtocolDefs_h
enum BlynkCmd
{
BLYNK_CMD_RESPONSE = 0,
BLYNK_CMD_REGISTER = 1,
BLYNK_CMD_LOGIN = 2,
BLYNK_CMD_SAVE_PROF = 3,
BLYNK_CMD_LOAD_PROF = 4,
BLYNK_CMD_GET_TOKEN = 5,
BLYNK_CMD_PING = 6,
BLYNK_CMD_ACTIVATE = 7,
BLYNK_CMD_DEACTIVATE = 8,
BLYNK_CMD_REFRESH = 9,
BLYNK_CMD_GET_GRAPH_DATA = 10,
BLYNK_CMD_GET_GRAPH_DATA_RESPONSE = 11,
BLYNK_CMD_TWEET = 12,
BLYNK_CMD_EMAIL = 13,
BLYNK_CMD_NOTIFY = 14,
BLYNK_CMD_BRIDGE = 15,
BLYNK_CMD_HARDWARE_SYNC = 16,
BLYNK_CMD_INTERNAL = 17,
BLYNK_CMD_SMS = 18,
BLYNK_CMD_PROPERTY = 19,
BLYNK_CMD_HARDWARE = 20,
BLYNK_CMD_CREATE_DASH = 21,
BLYNK_CMD_SAVE_DASH = 22,
BLYNK_CMD_DELETE_DASH = 23,
BLYNK_CMD_LOAD_PROF_GZ = 24,
BLYNK_CMD_SYNC = 25,
BLYNK_CMD_SHARING = 26,
BLYNK_CMD_ADD_PUSH_TOKEN = 27,
//sharing commands
BLYNK_CMD_GET_SHARED_DASH = 29,
BLYNK_CMD_GET_SHARE_TOKEN = 30,
BLYNK_CMD_REFRESH_SHARE_TOKEN = 31,
BLYNK_CMD_SHARE_LOGIN = 32,
BLYNK_CMD_REDIRECT = 41,
BLYNK_CMD_DEBUG_PRINT = 55,
BLYNK_CMD_EVENT_LOG = 64
};
enum BlynkStatus
{
BLYNK_SUCCESS = 200,
BLYNK_QUOTA_LIMIT_EXCEPTION = 1,
BLYNK_ILLEGAL_COMMAND = 2,
BLYNK_NOT_REGISTERED = 3,
BLYNK_ALREADY_REGISTERED = 4,
BLYNK_NOT_AUTHENTICATED = 5,
BLYNK_NOT_ALLOWED = 6,
BLYNK_DEVICE_NOT_IN_NETWORK = 7,
BLYNK_NO_ACTIVE_DASHBOARD = 8,
BLYNK_INVALID_TOKEN = 9,
BLYNK_ILLEGAL_COMMAND_BODY = 11,
BLYNK_GET_GRAPH_DATA_EXCEPTION = 12,
BLYNK_NO_DATA_EXCEPTION = 17,
BLYNK_DEVICE_WENT_OFFLINE = 18,
BLYNK_SERVER_EXCEPTION = 19,
BLYNK_NTF_INVALID_BODY = 13,
BLYNK_NTF_NOT_AUTHORIZED = 14,
BLYNK_NTF_ECXEPTION = 15,
BLYNK_TIMEOUT = 16,
BLYNK_NOT_SUPPORTED_VERSION = 20,
BLYNK_ENERGY_LIMIT = 21
};
struct BlynkHeader
{
uint8_t type;
uint16_t msg_id;
uint16_t length;
}
BLYNK_ATTR_PACKED;
#if !defined(htons) && (defined(ARDUINO) || defined(ESP8266) || defined(PARTICLE) || defined(__MBED__))
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) )
#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \
((x)<< 8 & 0x00FF0000UL) | \
((x)>> 8 & 0x0000FF00UL) | \
((x)>>24 & 0x000000FFUL) )
#define ntohs(x) htons(x)
#define ntohl(x) htonl(x)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define htons(x) (x)
#define htonl(x) (x)
#define ntohs(x) (x)
#define ntohl(x) (x)
#else
#error byte order problem
#endif
#endif
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define BLYNK_STR_16(a,b) ((uint16_t(a) << 0) | (uint16_t(b) << 8))
#define BLYNK_STR_32(a,b,c,d) ((uint32_t(a) << 0) | (uint32_t(b) << 8) | (uint32_t(c) << 16) | (uint32_t(d) << 24))
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define BLYNK_STR_16(a,b) ((uint16_t(b) << 0) | (uint16_t(a) << 8))
#define BLYNK_STR_32(a,b,c,d) ((uint32_t(d) << 0) | (uint32_t(c) << 8) | (uint32_t(b) << 16) | (uint32_t(a) << 24))
#else
#error byte order problem
#endif
#define BLYNK_HW_PM BLYNK_STR_16('p','m')
#define BLYNK_HW_DW BLYNK_STR_16('d','w')
#define BLYNK_HW_DR BLYNK_STR_16('d','r')
#define BLYNK_HW_AW BLYNK_STR_16('a','w')
#define BLYNK_HW_AR BLYNK_STR_16('a','r')
#define BLYNK_HW_VW BLYNK_STR_16('v','w')
#define BLYNK_HW_VR BLYNK_STR_16('v','r')
#define BLYNK_INT_RTC BLYNK_STR_32('r','t','c',0)
#define BLYNK_INT_OTA BLYNK_STR_32('o','t','a',0)
#define BLYNK_INT_ACON BLYNK_STR_32('a','c','o','n')
#define BLYNK_INT_ADIS BLYNK_STR_32('a','d','i','s')
#endif

View File

@@ -0,0 +1,47 @@
class BlynkStackOnly
{
protected:
BlynkStackOnly() {}
~BlynkStackOnly() {}
private:
/// @brief Declared as private to prevent usage of dynamic memory
void* operator new(size_t size);
/// @brief Declared as private to prevent usage of dynamic memory
void operator delete(void *p);
};
class BlynkNonCopyable
{
protected:
BlynkNonCopyable(){}
~BlynkNonCopyable(){}
private:
/// @brief Declared as private to prevent usage of copy constructor
BlynkNonCopyable(const BlynkNonCopyable&);
/// @brief Declared as private to prevent usage of assignment operator
BlynkNonCopyable& operator=(const BlynkNonCopyable&);
};
template<typename T>
class BlynkSingleton
: public BlynkNonCopyable
{
public:
/** @brief Returns the instance of the singleton type
When called for the first time, the singleton instance will be
created. All subsequent calls will return a reference to the
previously created instance.
@return The singleton instance
*/
static T* instance()
{
static T instance;
return &instance;
}
protected:
BlynkSingleton() {}
~BlynkSingleton() {}
};

View File

@@ -0,0 +1,291 @@
/*
* SimpleTimer.cpp
*
* SimpleTimer - A timer library for Arduino.
* Author: mromani@ottotecnica.com
* Copyright (c) 2010 OTTOTECNICA Italy
*
* Callback function parameters added & compiler warnings
* removed by Bill Knight <billk@rosw.com> 20March2017
*
* 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 "BlynkTimer.h"
#include <string.h>
// Select time function:
//static inline unsigned long elapsed() { return micros(); }
static inline unsigned long elapsed() { return BlynkMillis(); }
SimpleTimer::SimpleTimer()
: numTimers (-1)
{
}
void SimpleTimer::init() {
unsigned long current_millis = elapsed();
for (int i = 0; i < MAX_TIMERS; i++) {
memset(&timer[i], 0, sizeof (timer_t));
timer[i].prev_millis = current_millis;
}
numTimers = 0;
}
void SimpleTimer::run() {
int i;
unsigned long current_millis;
// get current time
current_millis = elapsed();
for (i = 0; i < MAX_TIMERS; i++) {
timer[i].toBeCalled = DEFCALL_DONTRUN;
// no callback == no timer, i.e. jump over empty slots
if (timer[i].callback != NULL) {
// is it time to process this timer ?
// see http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592
if ((current_millis - timer[i].prev_millis) >= timer[i].delay) {
unsigned long skipTimes = (current_millis - timer[i].prev_millis) / timer[i].delay;
// update time
timer[i].prev_millis += timer[i].delay * skipTimes;
// check if the timer callback has to be executed
if (timer[i].enabled) {
// "run forever" timers must always be executed
if (timer[i].maxNumRuns == RUN_FOREVER) {
timer[i].toBeCalled = DEFCALL_RUNONLY;
}
// other timers get executed the specified number of times
else if (timer[i].numRuns < timer[i].maxNumRuns) {
timer[i].toBeCalled = DEFCALL_RUNONLY;
timer[i].numRuns++;
// after the last run, delete the timer
if (timer[i].numRuns >= timer[i].maxNumRuns) {
timer[i].toBeCalled = DEFCALL_RUNANDDEL;
}
}
}
}
}
}
for (i = 0; i < MAX_TIMERS; i++) {
if (timer[i].toBeCalled == DEFCALL_DONTRUN)
continue;
if (timer[i].hasParam)
(*(timer_callback_p)timer[i].callback)(timer[i].param);
else
(*(timer_callback)timer[i].callback)();
if (timer[i].toBeCalled == DEFCALL_RUNANDDEL)
deleteTimer(i);
}
}
// find the first available slot
// return -1 if none found
int SimpleTimer::findFirstFreeSlot() {
// all slots are used
if (numTimers >= MAX_TIMERS) {
return -1;
}
// return the first slot with no callback (i.e. free)
for (int i = 0; i < MAX_TIMERS; i++) {
if (timer[i].callback == NULL) {
return i;
}
}
// no free slots found
return -1;
}
int SimpleTimer::setupTimer(unsigned long d, void* f, void* p, bool h, unsigned n) {
int freeTimer;
if (numTimers < 0) {
init();
}
freeTimer = findFirstFreeSlot();
if (freeTimer < 0) {
return -1;
}
if (f == NULL) {
return -1;
}
timer[freeTimer].delay = d;
timer[freeTimer].callback = f;
timer[freeTimer].param = p;
timer[freeTimer].hasParam = h;
timer[freeTimer].maxNumRuns = n;
timer[freeTimer].enabled = true;
timer[freeTimer].prev_millis = elapsed();
numTimers++;
return freeTimer;
}
int SimpleTimer::setTimer(unsigned long d, timer_callback f, unsigned n) {
return setupTimer(d, (void *)f, NULL, false, n);
}
int SimpleTimer::setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n) {
return setupTimer(d, (void *)f, p, true, n);
}
int SimpleTimer::setInterval(unsigned long d, timer_callback f) {
return setupTimer(d, (void *)f, NULL, false, RUN_FOREVER);
}
int SimpleTimer::setInterval(unsigned long d, timer_callback_p f, void* p) {
return setupTimer(d, (void *)f, p, true, RUN_FOREVER);
}
int SimpleTimer::setTimeout(unsigned long d, timer_callback f) {
return setupTimer(d, (void *)f, NULL, false, RUN_ONCE);
}
int SimpleTimer::setTimeout(unsigned long d, timer_callback_p f, void* p) {
return setupTimer(d, (void *)f, p, true, RUN_ONCE);
}
bool SimpleTimer::changeInterval(unsigned numTimer, unsigned long d) {
if (numTimer >= MAX_TIMERS) {
return false;
}
// Updates interval of existing specified timer
if (timer[numTimer].callback != NULL) {
timer[numTimer].delay = d;
timer[numTimer].prev_millis = elapsed();
return true;
}
// false return for non-used numTimer, no callback
return false;
}
void SimpleTimer::deleteTimer(unsigned timerId) {
if (timerId >= MAX_TIMERS) {
return;
}
// nothing to delete if no timers are in use
if (numTimers == 0) {
return;
}
// don't decrease the number of timers if the
// specified slot is already empty
if (timer[timerId].callback != NULL) {
memset(&timer[timerId], 0, sizeof (timer_t));
timer[timerId].prev_millis = elapsed();
// update number of timers
numTimers--;
}
}
// function contributed by code@rowansimms.com
void SimpleTimer::restartTimer(unsigned numTimer) {
if (numTimer >= MAX_TIMERS) {
return;
}
timer[numTimer].prev_millis = elapsed();
}
bool SimpleTimer::isEnabled(unsigned numTimer) {
if (numTimer >= MAX_TIMERS) {
return false;
}
return timer[numTimer].enabled;
}
void SimpleTimer::enable(unsigned numTimer) {
if (numTimer >= MAX_TIMERS) {
return;
}
timer[numTimer].enabled = true;
}
void SimpleTimer::disable(unsigned numTimer) {
if (numTimer >= MAX_TIMERS) {
return;
}
timer[numTimer].enabled = false;
}
void SimpleTimer::enableAll() {
// Enable all timers with a callback assigned (used)
for (int i = 0; i < MAX_TIMERS; i++) {
if (timer[i].callback != NULL && timer[i].numRuns == RUN_FOREVER) {
timer[i].enabled = true;
}
}
}
void SimpleTimer::disableAll() {
// Disable all timers with a callback assigned (used)
for (int i = 0; i < MAX_TIMERS; i++) {
if (timer[i].callback != NULL && timer[i].numRuns == RUN_FOREVER) {
timer[i].enabled = false;
}
}
}
void SimpleTimer::toggle(unsigned numTimer) {
if (numTimer >= MAX_TIMERS) {
return;
}
timer[numTimer].enabled = !timer[numTimer].enabled;
}
unsigned SimpleTimer::getNumTimers() {
return numTimers;
}

View File

@@ -0,0 +1,155 @@
/*
* SimpleTimer.h
*
* SimpleTimer - A timer library for Arduino.
* Author: mromani@ottotecnica.com
* Copyright (c) 2010 OTTOTECNICA Italy
*
* Modifications by Bill Knight <billk@rosw.com> 18March2017
*
* 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
*
*/
#ifndef BLYNKTIMER_H
#define BLYNKTIMER_H
#include "BlynkDebug.h"
// Replace SimpleTimer
#define SIMPLETIMER_H
#define SimpleTimer BlynkTimer
typedef void (*timer_callback)(void);
typedef void (*timer_callback_p)(void *);
class SimpleTimer {
public:
// maximum number of timers
const static int MAX_TIMERS = 16;
// setTimer() constants
const static int RUN_FOREVER = 0;
const static int RUN_ONCE = 1;
// constructor
SimpleTimer();
void init();
// this function must be called inside loop()
void run();
// Timer will call function 'f' every 'd' milliseconds forever
// returns the timer number (numTimer) on success or
// -1 on failure (f == NULL) or no free timers
int setInterval(unsigned long d, timer_callback f);
// Timer will call function 'f' with parameter 'p' every 'd' milliseconds forever
// returns the timer number (numTimer) on success or
// -1 on failure (f == NULL) or no free timers
int setInterval(unsigned long d, timer_callback_p f, void* p);
// Timer will call function 'f' after 'd' milliseconds one time
// returns the timer number (numTimer) on success or
// -1 on failure (f == NULL) or no free timers
int setTimeout(unsigned long d, timer_callback f);
// Timer will call function 'f' with parameter 'p' after 'd' milliseconds one time
// returns the timer number (numTimer) on success or
// -1 on failure (f == NULL) or no free timers
int setTimeout(unsigned long d, timer_callback_p f, void* p);
// Timer will call function 'f' every 'd' milliseconds 'n' times
// returns the timer number (numTimer) on success or
// -1 on failure (f == NULL) or no free timers
int setTimer(unsigned long d, timer_callback f, unsigned n);
// Timer will call function 'f' with parameter 'p' every 'd' milliseconds 'n' times
// returns the timer number (numTimer) on success or
// -1 on failure (f == NULL) or no free timers
int setTimer(unsigned long d, timer_callback_p f, void* p, unsigned n);
// updates interval of the specified timer
bool changeInterval(unsigned numTimer, unsigned long d);
// destroy the specified timer
void deleteTimer(unsigned numTimer);
// restart the specified timer
void restartTimer(unsigned numTimer);
// returns true if the specified timer is enabled
bool isEnabled(unsigned numTimer);
// enables the specified timer
void enable(unsigned numTimer);
// disables the specified timer
void disable(unsigned numTimer);
// enables all timers
void enableAll();
// disables all timers
void disableAll();
// enables the specified timer if it's currently disabled,
// and vice-versa
void toggle(unsigned numTimer);
// returns the number of used timers
unsigned getNumTimers();
// returns the number of available timers
unsigned getNumAvailableTimers() { return MAX_TIMERS - numTimers; };
private:
// deferred call constants
const static int DEFCALL_DONTRUN = 0; // don't call the callback function
const static int DEFCALL_RUNONLY = 1; // call the callback function but don't delete the timer
const static int DEFCALL_RUNANDDEL = 2; // call the callback function and delete the timer
// low level function to initialize and enable a new timer
// returns the timer number (numTimer) on success or
// -1 on failure (f == NULL) or no free timers
int setupTimer(unsigned long d, void* f, void* p, bool h, unsigned n);
// find the first available slot
int findFirstFreeSlot();
typedef struct {
unsigned long prev_millis; // value returned by the millis() function in the previous run() call
void* callback; // pointer to the callback function
void* param; // function parameter
bool hasParam; // true if callback takes a parameter
unsigned long delay; // delay value
unsigned maxNumRuns; // number of runs to be executed
unsigned numRuns; // number of executed runs
bool enabled; // true if enabled
unsigned toBeCalled; // deferred function call (sort of) - N.B.: only used in run()
} timer_t;
timer_t timer[MAX_TIMERS];
// actual number of timers in use (-1 means uninitialized)
int numTimers;
};
#endif

View File

@@ -0,0 +1,64 @@
/**
* @file BlynkUtility.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Jun 2015
* @brief Utility functions
*
*/
#ifndef BlynkUtility_h
#define BlynkUtility_h
template<class T>
const T& BlynkMin(const T& a, const T& b)
{
return (b < a) ? b : a;
}
template<class T>
const T& BlynkMax(const T& a, const T& b)
{
return (b < a) ? a : b;
}
template <class T>
T BlynkMathMap(T x, T in_min, T in_max, T out_min, T out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
template <class T>
T BlynkMathClamp(T val, T low, T high)
{
return (val < low) ? low : ((val > high) ? high : val);
}
template <unsigned WSIZE, typename T>
void BlynkAverageSample (T& avg, const T& input) {
avg -= avg/WSIZE;
const T add = input/WSIZE;
// Fix for shorter delays
if (add > 0)
avg += add;
else
avg -= 1;
}
class BlynkHelperAutoInc {
public:
BlynkHelperAutoInc(uint8_t& counter) : c(counter) { ++c; }
~BlynkHelperAutoInc() { --c; }
private:
uint8_t& c;
};
#define BlynkBitSet(value, bit) ((value) |= (1UL << (bit)))
#define BlynkBitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define BlynkBitRead(value, bit) (((value) >> (bit)) & 0x01)
#define BlynkBitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
#endif

View File

@@ -0,0 +1,102 @@
/**
* @file BlynkWiFiCommon.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Jan 2015
* @brief
*
*/
#ifndef BlynkWiFiCommon_h
#define BlynkWiFiCommon_h
#ifndef BLYNK_INFO_CONNECTION
#define BLYNK_INFO_CONNECTION "WiFi"
#endif
#include "BlynkApiArduino.h"
#include "BlynkProtocol.h"
#include "BlynkArduinoClient.h"
class BlynkWifiCommon
: public BlynkProtocol<BlynkArduinoClient>
{
typedef BlynkProtocol<BlynkArduinoClient> Base;
public:
BlynkWifiCommon(BlynkArduinoClient& transp)
: Base(transp)
{}
void connectWiFi(const char* ssid, const char* pass)
{
int status = WL_IDLE_STATUS;
// check for the presence of the shield:
if (WiFi.status() == WL_NO_SHIELD) {
BLYNK_FATAL("WiFi shield not present");
}
#ifdef BLYNK_DEBUG
BLYNK_LOG2(BLYNK_F("WiFi firmware: "), WiFi.firmwareVersion());
#endif
// attempt to connect to Wifi network:
while (true) {
BLYNK_LOG2(BLYNK_F("Connecting to "), ssid);
if (pass && strlen(pass)) {
status = WiFi.begin((char*)ssid, (char*)pass);
} else {
status = WiFi.begin((char*)ssid);
}
if (status == WL_CONNECTED) {
break;
} else {
BlynkDelay(5000);
}
}
IPAddress myip = WiFi.localIP();
BLYNK_LOG_IP("IP: ", myip);
}
void config(const char* auth,
const char* domain = BLYNK_DEFAULT_DOMAIN,
uint16_t port = BLYNK_DEFAULT_PORT)
{
Base::begin(auth);
this->conn.begin(domain, port);
}
void config(const char* auth,
IPAddress ip,
uint16_t port = BLYNK_DEFAULT_PORT)
{
Base::begin(auth);
this->conn.begin(ip, port);
}
void begin(const char* auth,
const char* ssid,
const char* pass,
const char* domain = BLYNK_DEFAULT_DOMAIN,
uint16_t port = BLYNK_DEFAULT_PORT)
{
connectWiFi(ssid, pass);
config(auth, domain, port);
while(this->connect() != true) {}
}
void begin(const char* auth,
const char* ssid,
const char* pass,
IPAddress ip,
uint16_t port = BLYNK_DEFAULT_PORT)
{
connectWiFi(ssid, pass);
config(auth, ip, port);
while(this->connect() != true) {}
}
};
#endif

View File

@@ -0,0 +1,62 @@
/**
* @file BlynkWidgetBase.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy
* @date Nov 2016
* @brief
*/
#ifndef BlynkWidgetBase_h
#define BlynkWidgetBase_h
#include "BlynkApi.h"
class BlynkWidgetBase
{
public:
BlynkWidgetBase(uint8_t vPin) : mPin(vPin) {}
void setVPin(uint8_t vPin) { mPin = vPin; }
void onWrite(BlynkReq BLYNK_UNUSED &request, const BlynkParam BLYNK_UNUSED &param) {
BLYNK_LOG1(BLYNK_F("BlynkWidgetBase::onWrite should not be called"));
}
template<typename... Args>
void setLabel(Args... args) {
Blynk.setProperty(mPin, "label", args...);
}
template<typename... Args>
void setColor(Args... args) {
Blynk.setProperty(mPin, "color", args...);
}
template<typename... Args>
void setMin(Args... args) {
Blynk.setProperty(mPin, "min", args...);
}
template<typename... Args>
void setMax(Args... args) {
Blynk.setProperty(mPin, "max", args...);
}
protected:
uint8_t mPin;
};
class BlynkAttachWidgetHelper {
public:
template<typename T>
explicit BlynkAttachWidgetHelper(T& widget, uint8_t vPin) {
widget.setVPin(vPin);
}
};
// Could use __attribute__ ((constructor)), but hope for better portability
#define BLYNK_ATTACH_WIDGET(widget, pin) \
BlynkAttachWidgetHelper BLYNK_CONCAT2(blnk_widget_helper_, __COUNTER__)((widget), (pin)); \
BLYNK_WRITE(pin) { (widget).onWrite(request, param); }
#endif

View File

@@ -0,0 +1,198 @@
#include "BlynkDebug.h"
#include "BlynkDateTime.h"
#if !defined(BLYNK_NO_FLOAT) && defined(BLYNK_USE_INTERNAL_DTOSTRF)
#include <string.h>
#include <math.h>
#include <stdio.h>
char* dtostrf_internal(double number, signed char BLYNK_UNUSED width, unsigned char prec, char *s) {
if(isnan(number)) {
strcpy(s, "nan");
return s;
}
if(isinf(number)) {
strcpy(s, "inf");
return s;
}
if(number > 4294967040.0 || number < -4294967040.0) {
strcpy(s, "ovf");
return s;
}
char* out = s;
// Handle negative numbers
if(number < 0.0) {
*out = '-';
++out;
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
for(uint8_t i = 0; i < prec; ++i) {
rounding /= 10.0;
}
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long) number;
double remainder = number - (double) int_part;
out += sprintf(out, "%lu", int_part);
// Print the decimal point, but only if there are digits beyond
if(prec > 0) {
*out = '.';
++out;
}
while(prec-- > 0) {
remainder *= 10.0;
if((int)remainder == 0) {
*out = '0';
++out;
}
}
sprintf(out, "%d", (int) remainder);
return s;
}
#endif
#define YEAR_0 1900
#define YEAR_EPOCH 1970
#define SECS_IN_DAY (24L * 60L * 60L)
#define IS_LEAP_YEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400)))
#define YEAR_DAYS(year) (IS_LEAP_YEAR(year) ? 366 : 365)
#define TIME_MAX 2147483647L
static const int month_tab[2][12] = {
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
struct blynk_tm* blynk_gmtime_r(const blynk_time_t* t, struct blynk_tm *tm) {
blynk_time_t time = *t;
unsigned long dayclock, dayno;
int year = YEAR_EPOCH;
dayclock = (unsigned long) time % SECS_IN_DAY;
dayno = (unsigned long) time / SECS_IN_DAY;
tm->tm_sec = dayclock % 60;
tm->tm_min = (dayclock % 3600) / 60;
tm->tm_hour = dayclock / 3600;
tm->tm_wday = (dayno + 4) % 7;
while (dayno >= (unsigned long) YEAR_DAYS(year)) {
dayno -= YEAR_DAYS(year);
year++;
}
tm->tm_year = year - YEAR_0;
tm->tm_yday = dayno;
tm->tm_mon = 0;
while (dayno >= (unsigned long) month_tab[IS_LEAP_YEAR(year)][tm->tm_mon]) {
dayno -= month_tab[IS_LEAP_YEAR(year)][tm->tm_mon];
tm->tm_mon++;
}
tm->tm_mday = dayno + 1;
tm->tm_isdst = 0;
return tm;
}
blynk_time_t blynk_mk_gmtime(struct blynk_tm *tm) {
long day, year;
int tm_year;
int yday, month;
long seconds;
int overflow;
tm->tm_min += tm->tm_sec / 60;
tm->tm_sec %= 60;
if (tm->tm_sec < 0) {
tm->tm_sec += 60;
tm->tm_min--;
}
tm->tm_hour += tm->tm_min / 60;
tm->tm_min = tm->tm_min % 60;
if (tm->tm_min < 0) {
tm->tm_min += 60;
tm->tm_hour--;
}
day = tm->tm_hour / 24;
tm->tm_hour = tm->tm_hour % 24;
if (tm->tm_hour < 0) {
tm->tm_hour += 24;
day--;
}
tm->tm_year += tm->tm_mon / 12;
tm->tm_mon %= 12;
if (tm->tm_mon < 0) {
tm->tm_mon += 12;
tm->tm_year--;
}
day += (tm->tm_mday - 1);
while (day < 0) {
if (--tm->tm_mon < 0) {
tm->tm_year--;
tm->tm_mon = 11;
}
day += month_tab[IS_LEAP_YEAR(YEAR_0 + tm->tm_year)][tm->tm_mon];
}
while (day >= month_tab[IS_LEAP_YEAR(YEAR_0 + tm->tm_year)][tm->tm_mon]) {
day -= month_tab[IS_LEAP_YEAR(YEAR_0 + tm->tm_year)][tm->tm_mon];
if (++(tm->tm_mon) == 12) {
tm->tm_mon = 0;
tm->tm_year++;
}
}
tm->tm_mday = day + 1;
year = YEAR_EPOCH;
if (tm->tm_year < year - YEAR_0)
return (blynk_time_t) -1;
seconds = 0;
day = 0;
overflow = 0;
tm_year = tm->tm_year + YEAR_0;
if (TIME_MAX / 365 < tm_year - year)
overflow++;
day = (tm_year - year) * 365;
if (TIME_MAX - day < (tm_year - year) / 4 + 1)
overflow++;
day += (tm_year - year) / 4 + ((tm_year % 4) && tm_year % 4 < year % 4);
day -= (tm_year - year) / 100
+ ((tm_year % 100) && tm_year % 100 < year % 100);
day += (tm_year - year) / 400
+ ((tm_year % 400) && tm_year % 400 < year % 400);
yday = month = 0;
while (month < tm->tm_mon) {
yday += month_tab[IS_LEAP_YEAR(tm_year)][month];
month++;
}
yday += (tm->tm_mday - 1);
if (day + yday < 0)
overflow++;
day += yday;
tm->tm_yday = yday;
tm->tm_wday = (day + 4) % 7;
seconds = ((tm->tm_hour * 60L) + tm->tm_min) * 60L + tm->tm_sec;
if ((TIME_MAX - seconds) / SECS_IN_DAY < day)
overflow++;
seconds += day * SECS_IN_DAY;
if (overflow)
return (blynk_time_t) -1;
if ((blynk_time_t) seconds != seconds)
return (blynk_time_t) -1;
return (blynk_time_t) seconds;
}

View File

@@ -0,0 +1,96 @@
/**
* @file BlynkSimpleEsp32.h
* @author Volodymyr Shymanskyy
* @license This project is released under the MIT License (MIT)
* @copyright Copyright (c) 2015 Volodymyr Shymanskyy
* @date Oct 2016
* @brief
*
*/
#ifndef BlynkSimpleEsp_h
#define BlynkSimpleEsp_h
#define BLYNK_SEND_ATOMIC
#include "Blynk/BlynkApiArduino.h"
#include "Blynk/BlynkProtocol.h"
#include "Blynk/BlynkArduinoClient.h"
#ifdef ARDUINO_ARCH_ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
class BlynkWifi
: public BlynkProtocol<BlynkArduinoClient>
{
typedef BlynkProtocol<BlynkArduinoClient> Base;
public:
BlynkWifi(BlynkArduinoClient& transp)
: Base(transp)
{}
void connectWiFi(const char* ssid, const char* pass)
{
BLYNK_LOG2(BLYNK_F("Connecting to "), ssid);
WiFi.mode(WIFI_STA);
if (pass && strlen(pass)) {
WiFi.begin(ssid, pass);
} else {
WiFi.begin(ssid);
}
while (WiFi.status() != WL_CONNECTED) {
BlynkDelay(500);
}
BLYNK_LOG1(BLYNK_F("Connected to WiFi"));
IPAddress myip = WiFi.localIP();
BLYNK_LOG_IP("IP: ", myip);
}
void config(const char* auth,
const char* domain = BLYNK_DEFAULT_DOMAIN,
uint16_t port = BLYNK_DEFAULT_PORT)
{
Base::begin(auth);
this->conn.begin(domain, port);
}
void config(const char* auth,
IPAddress ip,
uint16_t port = BLYNK_DEFAULT_PORT)
{
Base::begin(auth);
this->conn.begin(ip, port);
}
void begin(const char* auth,
const char* ssid,
const char* pass,
const char* domain = BLYNK_DEFAULT_DOMAIN,
uint16_t port = BLYNK_DEFAULT_PORT)
{
connectWiFi(ssid, pass);
config(auth, domain, port);
while(this->connect() != true) {}
}
void begin(const char* auth,
const char* ssid,
const char* pass,
IPAddress ip,
uint16_t port = BLYNK_DEFAULT_PORT)
{
connectWiFi(ssid, pass);
config(auth, ip, port);
while(this->connect() != true) {}
}
};
static WiFiClient _blynkWifiClient;
static BlynkArduinoClient _blynkTransport(_blynkWifiClient);
BlynkWifi Blynk(_blynkTransport);
#endif

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Volodymyr Shymanskyy
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,82 @@
/*
* E131.cpp
*
* Project: E131 - E.131 (sACN) library for Arduino
* Copyright (c) 2015 Shelby Merrick
* http://www.forkineye.com
*
* This program is provided free for you to use in any way that you wish,
* subject to the laws and regulations where you are using it. Due diligence
* is strongly suggested before using this code. Please give credit where due.
*
* The Author makes no warranty of any kind, express or implied, with regard
* to this program or the documentation contained in this document. The
* Author shall not be liable in any event for incidental or consequential
* damages in connection with, or arising out of, the furnishing, performance
* or use of these programs.
*
*/
#include "E131.h"
#include <string.h>
/* E1.17 ACN Packet Identifier */
const byte E131::ACN_ID[12] = { 0x41, 0x53, 0x43, 0x2d, 0x45, 0x31, 0x2e, 0x31, 0x37, 0x00, 0x00, 0x00 };
/* Constructor */
E131::E131() {
#ifdef NO_DOUBLE_BUFFER
memset(pbuff1.raw, 0, sizeof(pbuff1.raw));
packet = &pbuff1;
pwbuff = packet;
#else
memset(pbuff1.raw, 0, sizeof(pbuff1.raw));
memset(pbuff2.raw, 0, sizeof(pbuff2.raw));
packet = &pbuff1;
pwbuff = &pbuff2;
#endif
stats.num_packets = 0;
stats.packet_errors = 0;
}
void E131::initUnicast() {
udp.begin(E131_DEFAULT_PORT);
}
void E131::initMulticast(uint16_t universe, uint8_t n) {
IPAddress address = IPAddress(239, 255, ((universe >> 8) & 0xff),
((universe >> 0) & 0xff));
#ifdef ARDUINO_ARCH_ESP32
ip4_addr_t ifaddr;
ip4_addr_t multicast_addr;
ifaddr.addr = static_cast<uint32_t>(WiFi.localIP());
for (uint8_t i = 1; i < n; i++) {
multicast_addr.addr = static_cast<uint32_t>(IPAddress(239, 255,
(((universe + i) >> 8) & 0xff), (((universe + i) >> 0)
& 0xff)));
igmp_joingroup(&ifaddr, &multicast_addr);
}
udp.beginMulticast(address, E131_DEFAULT_PORT);
#else
ip_addr_t ifaddr;
ip_addr_t multicast_addr;
ifaddr.addr = static_cast<uint32_t>(WiFi.localIP());
for (uint8_t i = 1; i < n; i++) {
multicast_addr.addr = static_cast<uint32_t>(IPAddress(239, 255,
(((universe + i) >> 8) & 0xff), (((universe + i) >> 0)
& 0xff)));
igmp_joingroup(&ifaddr, &multicast_addr);
}
udp.beginMulticast(WiFi.localIP(), address, E131_DEFAULT_PORT);
#endif
}
void E131::begin(e131_listen_t type, uint16_t universe, uint8_t n) {
if (type == E131_UNICAST)
initUnicast();
if (type == E131_MULTICAST)
initMulticast(universe, n);
}

View File

@@ -0,0 +1,196 @@
/*
* E131.h
*
* Project: E131 - E.131 (sACN) library for Arduino
* Copyright (c) 2015 Shelby Merrick
* http://www.forkineye.com
*
* This program is provided free for you to use in any way that you wish,
* subject to the laws and regulations where you are using it. Due diligence
* is strongly suggested before using this code. Please give credit where due.
*
* The Author makes no warranty of any kind, express or implied, with regard
* to this program or the documentation contained in this document. The
* Author shall not be liable in any event for incidental or consequential
* damages in connection with, or arising out of, the furnishing, performance
* or use of these programs.
*
*/
#ifndef E131_H_
#define E131_H_
#include "Arduino.h"
/* Network interface detection. WiFi for ESP8266 and Ethernet for AVR */
#if defined (ARDUINO_ARCH_ESP8266)
# include <ESP8266WiFi.h>
# define NO_DOUBLE_BUFFER
#elif defined (ARDUINO_ARCH_ESP32)
# include <WiFi.h>
#endif
# include <WiFiUdp.h>
# include <lwip/ip_addr.h>
# include <lwip/igmp.h>
# define _UDP WiFiUDP
/* Defaults */
#define E131_DEFAULT_PORT 5568
/* E1.31 Packet Offsets */
#define E131_ROOT_PREAMBLE_SIZE 0
#define E131_ROOT_POSTAMBLE_SIZE 2
#define E131_ROOT_ID 4
#define E131_ROOT_FLENGTH 16
#define E131_ROOT_VECTOR 18
#define E131_ROOT_CID 22
#define E131_FRAME_FLENGTH 38
#define E131_FRAME_VECTOR 40
#define E131_FRAME_SOURCE 44
#define E131_FRAME_PRIORITY 108
#define E131_FRAME_RESERVED 109
#define E131_FRAME_SEQ 111
#define E131_FRAME_OPT 112
#define E131_FRAME_UNIVERSE 113
#define E131_DMP_FLENGTH 115
#define E131_DMP_VECTOR 117
#define E131_DMP_TYPE 118
#define E131_DMP_ADDR_FIRST 119
#define E131_DMP_ADDR_INC 121
#define E131_DMP_COUNT 123
#define E131_DMP_DATA 125
/* E1.31 Packet Structure */
typedef union {
struct {
/* Root Layer */
uint16_t preamble_size;
uint16_t postamble_size;
uint8_t acn_id[12];
uint16_t root_flength;
uint32_t root_vector;
uint8_t cid[16];
/* Frame Layer */
uint16_t frame_flength;
uint32_t frame_vector;
uint8_t source_name[64];
uint8_t priority;
uint16_t reserved;
uint8_t sequence_number;
uint8_t options;
uint16_t universe;
/* DMP Layer */
uint16_t dmp_flength;
uint8_t dmp_vector;
uint8_t type;
uint16_t first_address;
uint16_t address_increment;
uint16_t property_value_count;
uint8_t property_values[513];
} __attribute__((packed));
uint8_t raw[638];
} e131_packet_t;
/* Error Types */
typedef enum {
ERROR_NONE,
ERROR_IGNORE,
ERROR_ACN_ID,
ERROR_PACKET_SIZE,
ERROR_VECTOR_ROOT,
ERROR_VECTOR_FRAME,
ERROR_VECTOR_DMP
} e131_error_t;
/* E1.31 Listener Types */
typedef enum {
E131_UNICAST,
E131_MULTICAST
} e131_listen_t;
/* Status structure */
typedef struct {
uint32_t num_packets;
uint32_t packet_errors;
IPAddress last_clientIP;
uint16_t last_clientPort;
} e131_stats_t;
class E131 {
private:
/* Constants for packet validation */
static const uint8_t ACN_ID[];
static const uint32_t VECTOR_ROOT = 4;
static const uint32_t VECTOR_FRAME = 2;
static const uint8_t VECTOR_DMP = 2;
e131_packet_t pbuff1; /* Packet buffer */
#ifndef NO_DOUBLE_BUFFER
e131_packet_t pbuff2; /* Double buffer */
#endif
e131_packet_t *pwbuff; /* Pointer to working packet buffer */
_UDP udp; /* UDP handle */
/* Internal Initializers */
void initUnicast();
void initMulticast(uint16_t universe, uint8_t n = 1);
public:
uint8_t *data; /* Pointer to DMX channel data */
uint16_t universe; /* DMX Universe of last valid packet */
e131_packet_t *packet; /* Pointer to last valid packet */
e131_stats_t stats; /* Statistics tracker */
E131();
/* Generic UDP listener, no physical or IP configuration */
void begin(e131_listen_t type, uint16_t universe = 1, uint8_t n = 1);
/* Main packet parser */
inline uint16_t parsePacket() {
e131_error_t error;
uint16_t retval = 0;
int size = udp.parsePacket();
if (size) {
udp.readBytes(pwbuff->raw, size);
error = validate();
if (!error) {
#ifndef NO_DOUBLE_BUFFER
e131_packet_t *swap = packet;
packet = pwbuff;
pwbuff = swap;
#endif
universe = htons(packet->universe);
data = packet->property_values + 1;
retval = htons(packet->property_value_count) - 1;
stats.num_packets++;
stats.last_clientIP = udp.remoteIP();
stats.last_clientPort = udp.remotePort();
}
}
return retval;
}
/* Packet validater */
inline e131_error_t validate() {
if (memcmp(pwbuff->acn_id, ACN_ID, sizeof(pwbuff->acn_id)))
return ERROR_ACN_ID;
if (htonl(pwbuff->root_vector) != VECTOR_ROOT)
return ERROR_VECTOR_ROOT;
if (htonl(pwbuff->frame_vector) != VECTOR_FRAME)
return ERROR_VECTOR_FRAME;
if (pwbuff->dmp_vector != VECTOR_DMP)
return ERROR_VECTOR_DMP;
if (pwbuff->property_values[0] != 0)
return ERROR_IGNORE;
return ERROR_NONE;
}
};
#endif /* E131_H_ */

View File

@@ -90,8 +90,8 @@ WebServer::~WebServer() {
void WebServer::begin() {
_currentStatus = HC_NONE;
_server.begin();
if(!_headerKeysCount)
collectHeaders(0, 0);
//if(!_headerKeysCount)
//collectHeaders(0, 0);
}
bool WebServer::authenticate(const char * username, const char * password){
@@ -408,15 +408,13 @@ String WebServer::header(String name) {
return String();
}
void WebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) {
_headerKeysCount = headerKeysCount + 1;
if (_currentHeaders)
delete[]_currentHeaders;
_currentHeaders = new RequestArgument[_headerKeysCount];
//Modified by Aircoookie to work for WLED
void WebServer::collectHeaders(String headerKey) {
_headerKeysCount = 2;
if (_currentHeaders) delete[]_currentHeaders;
_currentHeaders = new RequestArgument[2];
_currentHeaders[0].key = AUTHORIZATION_HEADER;
for (int i = 1; i < _headerKeysCount; i++){
_currentHeaders[i].key = headerKeys[i-1];
}
_currentHeaders[1].key = headerKey;
}
String WebServer::header(int i) {

View File

@@ -105,7 +105,7 @@ public:
String argName(int i); // get request argument name by number
int args(); // get arguments count
bool hasArg(String name); // check if argument exists
void collectHeaders(const char* headerKeys[], const size_t headerKeysCount); // set the request headers to collect
void collectHeaders(String headerKey); // set the request headers to collect
String header(String name); // get request header value by name
String header(int i); // get request header value by number
String headerName(int i); // get request header name by number

View File

@@ -3,10 +3,14 @@
*/
/*
* @title WLED project sketch
* @version 0.6.0
* @version 0.7.1
* @author Christian Schwinne
*/
//ESP8266-01 got too little storage space to work with all features of WLED. To use it, you must use ESP8266 Arduino Core v2.3.0 and the setting 512K(64K SPIFFS).
//Uncomment the following line to disable some features (currently Mobile UI) to compile for ESP8266-01
//#define WLED_FLASH_512K_MODE
#include <Arduino.h>
#ifdef ARDUINO_ARCH_ESP32
#include <WiFi.h>
@@ -31,17 +35,16 @@
#include "htmls01.h"
#include "htmls02.h"
#include "WS2812FX.h"
#include "src/dependencies/blynk/BlynkSimpleEsp.h"
#include "src/dependencies/e131/E131.h"
//version in format yymmddb (b = daily build)
#define VERSION 1803151
const String versionString = "0.6.0";
#define VERSION 1808111
char versionString[] = "0.7.1";
//AP and OTA default passwords (change them!)
String apPass = "wled1234";
String otaPass = "wledota";
//If you have an RGBW strip, also uncomment first line in WS2812FX.h!
bool useRGBW = false;
char apPass[65] = "wled1234";
char otaPass[33] = "wledota";
//spiffs FS only useful for debug (only ESP8266)
//#define USEFS
@@ -50,20 +53,21 @@ bool useRGBW = false;
//#define DEBUG
//Hardware-settings (only changeble via code)
#define LEDCOUNT 255 //maximum, exact count set-able via settings
#define PIN 2 //strip pin. Only change for ESP32
byte buttonPin = 0; //needs pull-up
byte auxPin = 15; //use e.g. for external relay
byte auxDefaultState = 0; //0: input 1: high 2: low
byte auxTriggeredState = 0; //0: input 1: high 2: low
//Default CONFIG
String serverDescription = versionString;
char serverDescription[33] = "WLED Light";
byte currentTheme = 0;
String clientSSID = "Your_Network";
String clientPass = "";
String cmDNS = "led";
byte ledCount = 10; //lowered to prevent accidental overcurrent
String apSSID = ""; //AP off by default (unless setup)
byte uiConfiguration = 0; //0: auto 1: classic 2: mobile
char clientSSID[33] = "Your_Network";
char clientPass[65] = "";
char cmDNS[33] = "led";
uint16_t ledCount = 10; //lowered to prevent accidental overcurrent
char apSSID[65] = ""; //AP off by default (unless setup)
byte apChannel = 1;
byte apHide = 0;
byte apWaitTimeSecs = 32;
@@ -72,9 +76,9 @@ IPAddress staticIP(0, 0, 0, 0);
IPAddress staticGateway(0, 0, 0, 0);
IPAddress staticSubnet(255, 255, 255, 0);
IPAddress staticDNS(8, 8, 8, 8); //only for NTP
bool useHSB = false, useHSBDefault = false;
bool useHSB = true, useHSBDefault = true, useRGBW = false, autoRGBtoRGBW = false;
bool turnOnAtBoot = true;
bool initLedsLast = false;
bool initLedsLast = false, skipFirstLed = false;
byte bootPreset = 0;
byte colS[]{255, 159, 0};
byte colSecS[]{0, 0, 0};
@@ -84,7 +88,8 @@ byte briS = 127;
byte nightlightTargetBri = 0;
bool fadeTransition = true;
bool sweepTransition = false, sweepDirection = true;
uint16_t transitionDelay = 1200;
bool disableSecTransition = true;
uint16_t transitionDelay = 1200, transitionDelayDefault = transitionDelay;
bool reverseMode = false;
bool otaLock = false, wifiLock = false;
bool aOtaEnabled = true;
@@ -94,25 +99,25 @@ bool receiveNotifications = true, receiveNotificationBrightness = true, receiveN
byte briMultiplier = 100;
byte nightlightDelayMins = 60;
bool nightlightFade = true;
uint16_t udpPort = 21324;
uint16_t udpPort = 21324, udpRgbPort = 19446;
byte effectDefault = 0;
byte effectSpeedDefault = 75;
byte effectIntensityDefault = 128;
//NTP stuff
bool ntpEnabled = false;
String ntpServerName = "0.wled.pool.ntp.org";
char ntpServerName[] = "0.wled.pool.ntp.org";
//custom chase
byte ccNumPrimary = 2;
byte ccNumSecondary = 4;
byte ccIndex1 = 0;
byte ccIndex2 = ledCount -1;
uint16_t ccIndex2 = ledCount -1;
bool ccFromStart = true, ccFromEnd = false;
byte ccStep = 1;
byte ccStart = 0;
//alexa
bool alexaEnabled = true;
String alexaInvocationName = "Light";
char alexaInvocationName[33] = "Light";
byte macroBoot = 0, macroNl = 0;
byte macroAlexaOn = 0, macroAlexaOff = 0;
@@ -120,26 +125,28 @@ byte macroButton = 0, macroCountdown = 0, macroLongPress = 0;
unsigned long countdownTime = 1514764800L;
double transitionResolution = 0.011;
//hue
bool huePollingEnabled = false, hueAttempt = false;
uint16_t huePollIntervalMs = 2500;
String hueApiKey = "api";
char hueApiKey[65] = "api";
byte huePollLightId = 1;
IPAddress hueIP = (0,0,0,0);
bool notifyHue = true;
bool hueApplyOnOff = true, hueApplyBri = true, hueApplyColor = true;
uint16_t userVar0 = 0, userVar1 = 0;
//Internal vars
byte col[]{0, 0, 0};
byte colOld[]{0, 0, 0};
byte colT[]{0, 0, 0};
byte colIT[]{0, 0, 0};
byte colSec[]{0, 0, 0};
byte colSecT[]{0, 0, 0};
byte colSecOld[]{0, 0, 0};
byte colSecIT[]{0, 0, 0};
byte white, whiteOld, whiteT, whiteIT;
byte whiteSec, whiteSecIT;
byte white = 0, whiteOld, whiteT, whiteIT;
byte whiteSec = 0, whiteSecOld, whiteSecT, whiteSecIT;
byte lastRandomIndex = 0;
uint16_t transitionDelayTemp = transitionDelay;
unsigned long transitionStartTime;
@@ -158,24 +165,24 @@ byte notificationSentCallMode = 0;
bool notificationTwoRequired = false;
bool nightlightActive = false;
bool nightlightActiveOld = false;
uint32_t nightlightDelayMs;
byte briNlT;
uint32_t nightlightDelayMs = 10;
byte briNlT = 0;
byte effectCurrent = 0;
byte effectSpeed = 75;
byte effectIntensity = 128;
bool onlyAP = false;
bool udpConnected = false;
String cssCol[]={"","","","","",""};
String cssFont="Verdana";
bool udpConnected = false, udpRgbConnected = false;
char cssCol[9][5]={"","","","","",""};
char cssFont[33]="Verdana";
String cssColorString="";
//NTP stuff
bool ntpConnected = false;
byte currentTimezone = 0;
time_t local;
time_t local = 0;
int utcOffsetSecs = 0;
//hue
String hueError = "Inactive";
char hueError[25] = "Inactive";
uint16_t hueFailCount = 0;
float hueXLast=0, hueYLast=0;
uint16_t hueHueLast=0, hueCtLast=0;
@@ -183,6 +190,15 @@ byte hueSatLast=0, hueBriLast=0;
long hueLastRequestSent = 0;
uint32_t huePollIntervalMsTemp = huePollIntervalMs;
//blynk
char blynkApiKey[36] = "";
bool blynkEnabled = false;
//e1.31
bool e131Enabled = true;
byte e131Universe = 1;
bool e131Multicast = false;
//overlay stuff
byte overlayDefault = 0;
byte overlayCurrent = 0;
@@ -201,53 +217,66 @@ bool nixiePause;
byte countdownYear=19, countdownMonth=1, countdownDay=1, countdownHour=0, countdownMin=0, countdownSec=0; //year is actual year -2000
bool countdownOverTriggered = true;
//cronixie
String cronixieDisplay = "HHMMSS";
char cronixieDisplay[] = "HHMMSS";
byte dP[]{0,0,0,0,0,0};
bool useAMPM = false;
bool cronixieBacklight = true;
bool countdownMode = false;
bool cronixieInit = false;
uint32_t arlsTimeoutMillis = 2500;
bool presetCyclingEnabled = false;
byte presetCycleMin = 1, presetCycleMax = 5;
uint16_t presetCycleTime = 1250;
unsigned long presetCycledTime = 0; byte presetCycCurr = presetCycleMin;
bool presetApplyBri = true, presetApplyCol = true, presetApplyFx = true;
bool saveCurrPresetCycConf = false;
uint16_t arlsTimeoutMillis = 2500;
bool arlsTimeout = false;
unsigned long arlsTimeoutTime;
bool receiveDirect = true, enableRealtimeUI = false;
bool arlsDisableGammaCorrection = true, arlsForceMaxBri = false;
IPAddress realtimeIP = (0,0,0,0);
unsigned long arlsTimeoutTime = 0;
byte auxTime = 0;
unsigned long auxStartTime;
bool auxActive, auxActiveBefore;
unsigned long auxStartTime = 0;
bool auxActive = false, auxActiveBefore = false;
bool showWelcomePage = false;
bool useGammaCorrectionBri = false;
bool useGammaCorrectionRGB = true;
int arlsOffset = -22; //10: -22 assuming arls52
int arlsOffset = 0;
//alexa udp
WiFiUDP UDP;
IPAddress ipMulti(239, 255, 255, 250);
unsigned int portMulti = 1900;
char packetBuffer[255];
String escapedMac;
//dns server
DNSServer dnsServer;
bool dnsActive = false;
//string temp buffer
#define OMAX 1750
char obuf[OMAX];
uint16_t olen = 0;
#ifdef ARDUINO_ARCH_ESP32
WebServer server(80);
#else
ESP8266WebServer server(80);
#endif
E131 e131;
HTTPClient hueClient;
ESP8266HTTPUpdateServer httpUpdater;
WiFiUDP notifierUdp;
WiFiUDP notifierUdp, rgbUdp;
WiFiUDP ntpUdp;
IPAddress ntpServerIP;
unsigned int ntpLocalPort = 2390;
const uint16_t NTP_PACKET_SIZE = 48;
byte ntpPacketBuffer[NTP_PACKET_SIZE];
#define NTP_PACKET_SIZE 48
unsigned long ntpLastSyncTime = 999000000L;
unsigned long ntpPacketSentTime = 999000000L;
WS2812FX strip = WS2812FX(LEDCOUNT);
WS2812FX strip = WS2812FX();
#ifdef DEBUG
#define DEBUG_PRINT(x) Serial.print (x)
@@ -292,14 +321,6 @@ String txd = "Please disable OTA Lock in security settings!";
void serveMessage(int,String,String,int=255);
void down()
{
briT = 0;
setAllLeds();
DEBUG_PRINTLN("MODULE TERMINATED");
while (1) {delay(1000);}
}
void reset()
{
briT = 0;
@@ -308,26 +329,44 @@ void reset()
ESP.restart();
}
bool oappend(char* txt) //append new c string to temp buffer efficiently
{
uint16_t len = strlen(txt);
if (olen + len >= OMAX) return false; //buffer full
strcpy(obuf + olen, txt);
olen += len;
return true;
}
bool oappendi(int i) //append new number to temp buffer efficiently
{
char s[11];
sprintf(s,"%ld", i);
return oappend(s);
}
void setup() {
wledInit();
}
void loop() {
server.handleClient();
handleSerial();
handleNotifications();
handleTransitions();
userLoop();
yield();
handleButton();
handleNetworkTime();
if (!otaLock && aOtaEnabled) ArduinoOTA.handle();
if (aOtaEnabled) ArduinoOTA.handle();
handleAlexa();
handleOverlays();
if (!arlsTimeout) //block stuff if WARLS is enabled
if (!arlsTimeout) //block stuff if WARLS/Adalight is enabled
{
if (dnsActive) dnsServer.processNextRequest();
handleHue();
handleNightlight();
handleBlynk();
if (briT) strip.service(); //do not update strip if off, prevents flicker on ESP32
}

View File

@@ -6,7 +6,7 @@
#define EEPSIZE 3072
//eeprom Version code, enables default settings instead of 0 init on update
#define EEPVER 6
#define EEPVER 7
//0 -> old version, default
//1 -> 0.4p 1711272 and up
//2 -> 0.4p 1711302 and up
@@ -14,8 +14,11 @@
//4 -> 0.5.0 and up
//5 -> 0.5.1 and up
//6 -> 0.6.0 and up
//7 -> 0.7.1 and up
//todo add settings
/*
* Erase all configuration data
*/
void clearEEPROM()
{
for (int i = 0; i < EEPSIZE; i++)
@@ -25,59 +28,53 @@ void clearEEPROM()
EEPROM.commit();
}
/*
* Write configuration to flash
*/
void saveSettingsToEEPROM()
{
if (EEPROM.read(233) != 233) //set no first boot flag
{
clearEEPROM();
EEPROM.write(233, 233);
} else
{
showWelcomePage = false;
}
for (int i = 0; i < 32; ++i)
{
EEPROM.write(i, clientSSID.charAt(i));
EEPROM.write(i, clientSSID[i]);
}
for (int i = 32; i < 96; ++i)
{
EEPROM.write(i, clientPass.charAt(i-32));
EEPROM.write(i, clientPass[i-32]);
}
for (int i = 96; i < 128; ++i)
{
EEPROM.write(i, cmDNS.charAt(i-96));
EEPROM.write(i, cmDNS[i-96]);
}
for (int i = 128; i < 160; ++i)
{
EEPROM.write(i, apSSID.charAt(i-128));
EEPROM.write(i, apSSID[i-128]);
}
for (int i = 160; i < 224; ++i)
{
EEPROM.write(i, apPass.charAt(i-160));
EEPROM.write(i, apPass[i-160]);
}
EEPROM.write(224, nightlightDelayMins);
EEPROM.write(225, nightlightFade);
EEPROM.write(226, notifyDirectDefault);
EEPROM.write(227, apChannel);
EEPROM.write(228, apHide);
EEPROM.write(229, ledCount);
EEPROM.write(229, (ledCount >> 0) & 0xFF);
EEPROM.write(230, notifyButton);
EEPROM.write(231, notifyTwice);
EEPROM.write(232, buttonEnabled);
//233 reserved for first boot flag
EEPROM.write(234, staticIP[0]);
EEPROM.write(235, staticIP[1]);
EEPROM.write(236, staticIP[2]);
EEPROM.write(237, staticIP[3]);
EEPROM.write(238, staticGateway[0]);
EEPROM.write(239, staticGateway[1]);
EEPROM.write(240, staticGateway[2]);
EEPROM.write(241, staticGateway[3]);
EEPROM.write(242, staticSubnet[0]);
EEPROM.write(243, staticSubnet[1]);
EEPROM.write(244, staticSubnet[2]);
EEPROM.write(245, staticSubnet[3]);
for (int i = 0; i<4; i++) //ip addresses
{
EEPROM.write(234+i, staticIP[i]);
EEPROM.write(238+i, staticGateway[i]);
EEPROM.write(242+i, staticSubnet[i]);
}
EEPROM.write(246, colS[0]);
EEPROM.write(247, colS[1]);
EEPROM.write(248, colS[2]);
@@ -85,13 +82,13 @@ void saveSettingsToEEPROM()
EEPROM.write(250, receiveNotificationBrightness);
EEPROM.write(251, fadeTransition);
EEPROM.write(252, reverseMode);
EEPROM.write(253, (transitionDelay >> 0) & 0xFF);
EEPROM.write(254, (transitionDelay >> 8) & 0xFF);
EEPROM.write(253, (transitionDelayDefault >> 0) & 0xFF);
EEPROM.write(254, (transitionDelayDefault >> 8) & 0xFF);
EEPROM.write(255, briMultiplier);
//255,250,231,230,226 notifier bytes
for (int i = 256; i < 288; ++i)
{
EEPROM.write(i, otaPass.charAt(i-256));
EEPROM.write(i, otaPass[i-256]);
}
EEPROM.write(288, nightlightTargetBri);
EEPROM.write(289, otaLock);
@@ -99,7 +96,7 @@ void saveSettingsToEEPROM()
EEPROM.write(291, (udpPort >> 8) & 0xFF);
for (int i = 292; i < 324; ++i)
{
EEPROM.write(i, serverDescription.charAt(i-292));
EEPROM.write(i, serverDescription[i-292]);
}
EEPROM.write(324, effectDefault);
EEPROM.write(325, effectSpeedDefault);
@@ -113,7 +110,7 @@ void saveSettingsToEEPROM()
EEPROM.write(333, alexaEnabled);
for (int i = 334; i < 366; ++i)
{
EEPROM.write(i, alexaInvocationName.charAt(i-334));
EEPROM.write(i, alexaInvocationName[i-334]);
}
EEPROM.write(366, alexaNotify);
EEPROM.write(367, (arlsOffset>=0));
@@ -147,18 +144,20 @@ void saveSettingsToEEPROM()
EEPROM.write(395, (abs(utcOffsetSecs) >> 8) & 0xFF);
EEPROM.write(396, (utcOffsetSecs<0)); //is negative
EEPROM.write(397, initLedsLast);
EEPROM.write(398, (ledCount >> 8) & 0xFF);
EEPROM.write(399, disableSecTransition);
for (int k=0;k<6;k++){
int in = 900+k*8;
for (int i=in; i < in+8; ++i)
{
EEPROM.write(i, cssCol[k].charAt(i-in));
EEPROM.write(i, cssCol[i-in][k]);
}}
EEPROM.write(948,currentTheme);
for (int i = 950; i < 982; ++i)
{
EEPROM.write(i, cssFont.charAt(i-950));
EEPROM.write(i, cssFont[i-950]);
}
EEPROM.write(2048, huePollingEnabled);
@@ -169,7 +168,7 @@ void saveSettingsToEEPROM()
}
for (int i = 2054; i < 2100; ++i)
{
EEPROM.write(i, hueApiKey.charAt(i-2054));
EEPROM.write(i, hueApiKey[i-2054]);
}
EEPROM.write(2100, (huePollIntervalMs >> 0) & 0xFF);
EEPROM.write(2101, (huePollIntervalMs >> 8) & 0xFF);
@@ -195,7 +194,7 @@ void saveSettingsToEEPROM()
for (int i = 2165; i < 2171; ++i)
{
EEPROM.write(i, cronixieDisplay.charAt(i-2165));
EEPROM.write(i, cronixieDisplay[i-2165]);
}
EEPROM.write(2171, cronixieBacklight);
setCronixie();
@@ -207,49 +206,82 @@ void saveSettingsToEEPROM()
EEPROM.write(2179, macroLongPress);
EEPROM.write(2180, macroCountdown);
EEPROM.write(2181, macroNl);
EEPROM.write(2190, (e131Universe >> 0) & 0xFF);
EEPROM.write(2191, (e131Universe >> 8) & 0xFF);
EEPROM.write(2192, e131Multicast);
EEPROM.write(2193, (arlsTimeoutMillis >> 0) & 0xFF);
EEPROM.write(2194, (arlsTimeoutMillis >> 8) & 0xFF);
EEPROM.write(2195, arlsForceMaxBri);
EEPROM.write(2196, arlsDisableGammaCorrection);
EEPROM.write(2200,!receiveDirect);
EEPROM.write(2201,enableRealtimeUI);
EEPROM.write(2202,uiConfiguration);
EEPROM.write(2203,autoRGBtoRGBW);
EEPROM.write(2204,skipFirstLed);
if (saveCurrPresetCycConf)
{
EEPROM.write(2205,presetCyclingEnabled);
EEPROM.write(2206,(presetCycleTime >> 0) & 0xFF);
EEPROM.write(2207,(presetCycleTime >> 8) & 0xFF);
EEPROM.write(2208,presetCycleMin);
EEPROM.write(2209,presetCycleMax);
EEPROM.write(2210,presetApplyBri);
EEPROM.write(2211,presetApplyCol);
EEPROM.write(2212,presetApplyFx);
saveCurrPresetCycConf = false;
}
for (int i = 2220; i < 2255; ++i)
{
EEPROM.write(i, blynkApiKey[i-2220]);
}
EEPROM.commit();
}
/*
* Read all configuration from flash
*/
void loadSettingsFromEEPROM(bool first)
{
if (EEPROM.read(233) != 233) //first boot/reset to default
{
showWelcomePage=true;
saveSettingsToEEPROM();
return;
}
int lastEEPROMversion = EEPROM.read(377); //last EEPROM version before update
clientSSID = "";
for (int i = 0; i < 32; ++i)
{
if (EEPROM.read(i) == 0) break;
clientSSID += char(EEPROM.read(i));
clientSSID[i] = EEPROM.read(i);
if (clientSSID[i] == 0) break;
}
clientPass = "";
for (int i = 32; i < 96; ++i)
{
if (EEPROM.read(i) == 0) break;
clientPass += char(EEPROM.read(i));
clientPass[i-32] = EEPROM.read(i);
if (clientPass[i-32] == 0) break;
}
cmDNS = "";
for (int i = 96; i < 128; ++i)
{
if (EEPROM.read(i) == 0) break;
cmDNS += char(EEPROM.read(i));
cmDNS[i-96] = EEPROM.read(i);
if (cmDNS[i-96] == 0) break;
}
apSSID = "";
for (int i = 128; i < 160; ++i)
{
if (EEPROM.read(i) == 0) break;
apSSID += char(EEPROM.read(i));
apSSID[i-128] = EEPROM.read(i);
if (apSSID[i-128] == 0) break;
}
apPass = "";
for (int i = 160; i < 224; ++i)
{
if (EEPROM.read(i) == 0) break;
apPass += char(EEPROM.read(i));
apPass[i-160] = EEPROM.read(i);
if (apPass[i-160] == 0) break;
}
nightlightDelayMins = EEPROM.read(224);
nightlightFade = EEPROM.read(225);
@@ -259,7 +291,7 @@ void loadSettingsFromEEPROM(bool first)
if (apChannel > 13 || apChannel < 1) apChannel = 1;
apHide = EEPROM.read(228);
if (apHide > 1) apHide = 1;
ledCount = EEPROM.read(229); if (ledCount > LEDCOUNT) ledCount = LEDCOUNT;
ledCount = ((EEPROM.read(229) << 0) & 0xFF) + ((EEPROM.read(398) << 8) & 0xFF00); if (ledCount > 1200 || ledCount == 0) ledCount = 10;
notifyButton = EEPROM.read(230);
notifyTwice = EEPROM.read(231);
buttonEnabled = EEPROM.read(232);
@@ -286,22 +318,23 @@ void loadSettingsFromEEPROM(bool first)
receiveNotificationBrightness = EEPROM.read(250);
fadeTransition = EEPROM.read(251);
reverseMode = EEPROM.read(252);
transitionDelay = ((EEPROM.read(253) << 0) & 0xFF) + ((EEPROM.read(254) << 8) & 0xFF00);
transitionDelayDefault = ((EEPROM.read(253) << 0) & 0xFF) + ((EEPROM.read(254) << 8) & 0xFF00);
transitionDelay = transitionDelayDefault;
briMultiplier = EEPROM.read(255);
otaPass = "";
for (int i = 256; i < 288; ++i)
{
if (EEPROM.read(i) == 0) break;
otaPass += char(EEPROM.read(i));
otaPass[i-256] = EEPROM.read(i);
if (otaPass[i-256] == 0) break;
}
nightlightTargetBri = EEPROM.read(288);
otaLock = EEPROM.read(289);
udpPort = ((EEPROM.read(290) << 0) & 0xFF) + ((EEPROM.read(291) << 8) & 0xFF00);
serverDescription = "";
for (int i = 292; i < 324; ++i)
{
if (EEPROM.read(i) == 0) break;
serverDescription += char(EEPROM.read(i));
serverDescription[i-292] = EEPROM.read(i);
if (serverDescription[i-292] == 0) break;
}
effectDefault = EEPROM.read(324); effectCurrent = effectDefault;
effectSpeedDefault = EEPROM.read(325); effectSpeed = effectSpeedDefault;
@@ -312,11 +345,11 @@ void loadSettingsFromEEPROM(bool first)
useGammaCorrectionRGB = EEPROM.read(331);
overlayDefault = EEPROM.read(332);
alexaEnabled = EEPROM.read(333);
alexaInvocationName = "";
for (int i = 334; i < 366; ++i)
{
if (EEPROM.read(i) == 0) break;
alexaInvocationName += char(EEPROM.read(i));
alexaInvocationName[i-334] = EEPROM.read(i);
if (alexaInvocationName[i-334] == 0) break;
}
alexaNotify = EEPROM.read(366);
arlsOffset = EEPROM.read(368);
@@ -351,11 +384,11 @@ void loadSettingsFromEEPROM(bool first)
aOtaEnabled = EEPROM.read(390);
receiveNotificationColor = EEPROM.read(391);
receiveNotificationEffects = EEPROM.read(392);
cssFont = "";
for (int i = 950; i < 982; ++i)
{
if (EEPROM.read(i) == 0) break;
cssFont += char(EEPROM.read(i));
cssFont[i-950] = EEPROM.read(i);
if (cssFont[i-950] == 0) break;
}
} else //keep receiving notification behavior from pre0.5.0 after update
{
@@ -370,11 +403,11 @@ void loadSettingsFromEEPROM(bool first)
{
hueIP[i-2050] = EEPROM.read(i);
}
hueApiKey = "";
for (int i = 2054; i < 2100; ++i)
{
if (EEPROM.read(i) == 0) break;
hueApiKey += char(EEPROM.read(i));
hueApiKey[i-2054] = EEPROM.read(i);
if (hueApiKey[i-2054] == 0) break;
}
huePollIntervalMs = ((EEPROM.read(2100) << 0) & 0xFF) + ((EEPROM.read(2101) << 8) & 0xFF00);
notifyHue = EEPROM.read(2102);
@@ -398,11 +431,9 @@ void loadSettingsFromEEPROM(bool first)
countdownSec = EEPROM.read(2161);
setCountdown();
cronixieDisplay = "";
for (int i = 2165; i < 2171; ++i)
{
if (EEPROM.read(i) == 0) break;
cronixieDisplay += char(EEPROM.read(i));
cronixieDisplay[i-2165] = EEPROM.read(i);
}
cronixieBacklight = EEPROM.read(2171);
@@ -414,14 +445,53 @@ void loadSettingsFromEEPROM(bool first)
macroCountdown = EEPROM.read(2180);
macroNl = EEPROM.read(2181);
}
if (lastEEPROMversion > 6)
{
e131Universe = ((EEPROM.read(2190) << 0) & 0xFF) + ((EEPROM.read(2191) << 8) & 0xFF00);
e131Multicast = EEPROM.read(2192);
arlsTimeoutMillis = ((EEPROM.read(2193) << 0) & 0xFF) + ((EEPROM.read(2194) << 8) & 0xFF00);
arlsForceMaxBri = EEPROM.read(2195);
arlsDisableGammaCorrection = EEPROM.read(2196);
}
receiveDirect = !EEPROM.read(2200);
enableRealtimeUI = EEPROM.read(2201);
uiConfiguration = EEPROM.read(2202);
#ifdef WLED_FLASH_512K_MODE
uiConfiguration = 1;
//force default UI since mobile is unavailable
#endif
autoRGBtoRGBW = EEPROM.read(2203);
skipFirstLed = EEPROM.read(2204);
if (EEPROM.read(2210) || EEPROM.read(2211) || EEPROM.read(2212))
{
presetCyclingEnabled = EEPROM.read(2205);
presetCycleTime = ((EEPROM.read(2206) << 0) & 0xFF) + ((EEPROM.read(2207) << 8) & 0xFF00);
presetCycleMin = EEPROM.read(2208);
presetCycleMax = EEPROM.read(2209);
presetApplyBri = EEPROM.read(2210);
presetApplyCol = EEPROM.read(2211);
presetApplyFx = EEPROM.read(2212);
}
for (int i = 2220; i < 2255; ++i)
{
blynkApiKey[i-2220] = EEPROM.read(i);
if (blynkApiKey[i-2220] == 0) break;
}
bootPreset = EEPROM.read(389);
wifiLock = EEPROM.read(393);
utcOffsetSecs = ((EEPROM.read(394) << 0) & 0xFF) + ((EEPROM.read(395) << 8) & 0xFF00);
if (EEPROM.read(396)) utcOffsetSecs = -utcOffsetSecs; //negative
initLedsLast = EEPROM.read(397);
disableSecTransition = EEPROM.read(399);
//favorite setting memory (25 slots/ each 20byte)
//favorite setting (preset) memory (25 slots/ each 20byte)
//400 - 899 reserved
currentTheme = EEPROM.read(948);
@@ -430,7 +500,7 @@ void loadSettingsFromEEPROM(bool first)
for (int i=in; i < in+8; ++i)
{
if (EEPROM.read(i) == 0) break;
cssCol[k] += char(EEPROM.read(i));
cssCol[i-in][k] =EEPROM.read(i);
}}
//custom macro memory (16 slots/ each 64byte)
@@ -471,6 +541,7 @@ void applyPreset(byte index, bool loadBri, bool loadCol, bool loadFX)
}
if (loadFX)
{
byte lastfx = effectCurrent;
effectCurrent = EEPROM.read(i+10);
effectSpeed = EEPROM.read(i+11);
effectIntensity = EEPROM.read(i+16);
@@ -480,7 +551,7 @@ void applyPreset(byte index, bool loadBri, bool loadCol, bool loadFX)
ccFromStart = (EEPROM.read(i+14)<2);
ccStep = EEPROM.read(i+15);
strip.setCustomChase(ccIndex1, ccIndex2, ccStart, ccNumPrimary, ccNumSecondary, ccStep, ccFromStart, ccFromEnd);
strip.setMode(effectCurrent);
if (lastfx != effectCurrent) strip.setMode(effectCurrent);
strip.setSpeed(effectSpeed);
strip.setIntensity(effectIntensity);
}

View File

@@ -4,253 +4,305 @@
void XML_response()
{
String resp;
resp = resp + "<?xml version = \"1.0\" ?>";
resp = resp + "<vs>";
resp = resp + "<ac>";
olen = 0;
oappend("<?xml version = \"1.0\" ?><vs><ac>");
if (nightlightActive && nightlightFade)
{
resp = resp + briT;
oappendi(briT);
} else
{
resp = resp + bri;
oappendi(bri);
}
resp = resp + "</ac>";
oappend("</ac>");
for (int i = 0; i < 3; i++)
{
resp = resp + "<cl>";
resp = resp + col[i];
resp = resp + "</cl>";
oappend("<cl>");
oappendi(col[i]);
oappend("</cl>");
}
resp = resp + "<ns>";
resp = resp + notifyDirect;
resp = resp + "</ns><nr>";
resp = resp + receiveNotifications;
resp = resp + "</nr><nl>";
resp = resp + nightlightActive;
resp = resp + "</nl><nf>";
resp = resp + nightlightFade;
resp = resp + "</nf><nd>";
resp = resp + nightlightDelayMins;
resp = resp + "</nd><nt>";
resp = resp + nightlightTargetBri;
resp = resp + "</nt><fx>";
resp = resp + effectCurrent;
resp = resp + "</fx><sx>";
resp = resp + effectSpeed;
resp = resp + "</sx><ix>";
resp = resp + effectIntensity;
resp = resp + "</ix><wv>";
if (useRGBW) {
resp = resp + white;
oappend("<ns>");
oappendi(notifyDirect);
oappend("</ns><nr>");
oappendi(receiveNotifications);
oappend("</nr><nl>");
oappendi(nightlightActive);
oappend("</nl><nf>");
oappendi(nightlightFade);
oappend("</nf><nd>");
oappendi(nightlightDelayMins);
oappend("</nd><nt>");
oappendi(nightlightTargetBri);
oappend("</nt><fx>");
oappendi(effectCurrent);
oappend("</fx><sx>");
oappendi(effectSpeed);
oappend("</sx><ix>");
oappendi(effectIntensity);
oappend("</ix><wv>");
if (useRGBW && !autoRGBtoRGBW) {
oappendi(white);
} else {
resp = resp + "-1";
oappend("-1");
}
resp = resp + "</wv><md>";
resp = resp + useHSB;
resp = resp + "</md><ds>";
resp = resp + serverDescription;
resp = resp + "</ds>";
resp = resp + "</vs>";
server.send(200, "text/xml", resp);
oappend("</wv><md>");
oappendi(useHSB);
oappend("</md><ds>");
oappend(serverDescription);
oappend("</ds></vs>");
server.send(200, "text/xml", obuf);
}
String getSettings(byte subPage)
void sappend(char stype, char* key, int val) //append a setting to string buffer
{
char ds[] = "d.Sf.";
switch(stype)
{
case 'c': //checkbox
oappend(ds);
oappend(key);
oappend(".checked=");
oappendi(val);
oappend(";");
break;
case 'v': //numeric
oappend(ds);
oappend(key);
oappend(".value=");
oappendi(val);
oappend(";");
break;
case 'i': //selectedIndex
oappend(ds);
oappend(key);
oappend(".selectedIndex=");
oappendi(val);
oappend(";");
break;
}
}
void sappends(char stype, char* key, char* val) //append a string setting
{
switch(stype)
{
case 's': //string (we can interpret val as char*)
oappend("d.Sf.");
oappend(key);
oappend(".value=\"");
oappend(val);
oappend("\";");
break;
case 'm': //message
oappend("d.getElementsByClassName");
oappend(key);
oappend(".innerHTML=\"");
oappend(val);
oappend("\";");
break;
}
}
void getSettingsJS(byte subPage) //get values for settings form in javascript
{
//0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec
DEBUG_PRINT("settings resp");
DEBUG_PRINTLN(subPage);
String resp = "";
if (subPage <1 || subPage >6) return resp;
String ds = "d.Sf.";
String dg = "d.getElementsByClassName";
String v = ".value=";
String c = ".checked=";
String ih = ".innerHTML=";
String si = ".selectedIndex=";
olen = 0; obuf[0] = 0; //clear buffer
if (subPage <1 || subPage >6) return;
if (subPage == 1) {
resp += ds + "CS" + v + "\"" + clientSSID + "\";";
resp += ds + "CP" + v + "\"";
for (int i = 0; i < clientPass.length(); i++)
sappends('s',"CS",clientSSID);
byte l = strlen(clientPass);
char fpass[l+1]; //fill password field with ***
fpass[l] = 0;
memset(fpass,'*',l);
sappends('s',"CP",fpass);
char k[3]; k[2] = 0; //IP addresses
for (int i = 0; i<4; i++)
{
resp += "*";
k[1] = 48+i; //ascii 0,1,2,3
k[0] = 'I'; sappend('v',k,staticIP[i]);
k[0] = 'G'; sappend('v',k,staticGateway[i]);
k[0] = 'S'; sappend('v',k,staticSubnet[i]);
}
resp += "\";";
resp += ds + "I0" + v + staticIP[0] +";";
resp += ds + "I1" + v + staticIP[1] +";";
resp += ds + "I2" + v + staticIP[2] +";";
resp += ds + "I3" + v + staticIP[3] +";";
resp += ds + "G0" + v + staticGateway[0] +";";
resp += ds + "G1" + v + staticGateway[1] +";";
resp += ds + "G2" + v + staticGateway[2] +";";
resp += ds + "G3" + v + staticGateway[3] +";";
resp += ds + "S0" + v + staticSubnet[0] +";";
resp += ds + "S1" + v + staticSubnet[1] +";";
resp += ds + "S2" + v + staticSubnet[2] +";";
resp += ds + "S3" + v + staticSubnet[3] +";";
resp += ds + "CM" + v + "\"" + cmDNS + "\";";
resp += ds + "AT" + v + apWaitTimeSecs +";";
resp += ds + "AS" + v + "\"" + apSSID + "\";";
resp += ds + "AH" + c + apHide + ";";
resp += ds + "AP" + v + "\"";
for (int i = 0; i < apPass.length(); i++)
sappends('s',"CM",cmDNS);
sappend('v',"AT",apWaitTimeSecs);
sappends('s',"AS",apSSID);
sappend('c',"AH",apHide);
l = strlen(apPass);
char fapass[l+1]; //fill password field with ***
fapass[l] = 0;
memset(fapass,'*',l);
sappends('s',"AP",fapass);
sappend('v',"AC",apChannel);
if (WiFi.localIP()[0] != 0) //is connected
{
resp += "*";
}
resp += "\";";
resp += ds + "AC" + v + apChannel +";";
resp += dg + "(\"sip\")[0]" + ih + "\"";
if (!WiFi.localIP()[0] == 0)
{
resp += WiFi.localIP()[0];
resp += + ".";
resp += WiFi.localIP()[1];
resp += ".";
resp += WiFi.localIP()[2];
resp += ".";
resp += WiFi.localIP()[3];
char s[16];
IPAddress localIP = WiFi.localIP();
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
sappends('m',"(\"sip\")[0]",s);
} else
{
resp += "Not connected";
sappends('m',"(\"sip\")[0]","Not connected");
}
resp += "\";";
resp += dg + "(\"sip\")[1]" + ih + "\"";
if (!WiFi.softAPIP()[0] == 0)
if (WiFi.softAPIP()[0] != 0) //is active
{
resp += WiFi.softAPIP()[0];
resp += + ".";
resp += WiFi.softAPIP()[1];
resp += ".";
resp += WiFi.softAPIP()[2];
resp += ".";
resp += WiFi.softAPIP()[3];
char s[16];
IPAddress apIP = WiFi.softAPIP();
sprintf(s, "%d.%d.%d.%d", apIP[0], apIP[1], apIP[2], apIP[3]);
sappends('m',"(\"sip\")[1]",s);
} else
{
resp += "Not active";
sappends('m',"(\"sip\")[1]","Not active");
}
resp += "\";";
}
if (subPage == 2) {
resp += ds + "LC" + v + ledCount +";";
resp += ds + "CR" + v + colS[0] +";";
resp += ds + "CG" + v + colS[1] +";";
resp += ds + "CB" + v + colS[2] +";";
resp += ds + "CA" + v + briS +";";
if (useRGBW) {
resp += ds + "CW" + v + whiteS +";";
} else {
resp += ds + "CW" + v + "-1;";
}
resp += ds + "SR" + v + colSecS[0] +";";
resp += ds + "SG" + v + colSecS[1] +";";
resp += ds + "SB" + v + colSecS[2] +";";
resp += ds + "SW" + v + whiteSecS +";";
resp += ds + "BO" + c + turnOnAtBoot +";";
resp += ds + "BP" + v + bootPreset +";";
resp += ds + "FX" + v + effectDefault +";";
resp += ds + "SX" + v + effectSpeedDefault +";";
resp += ds + "IX" + v + effectIntensityDefault +";";
resp += ds + "GB" + c + useGammaCorrectionBri +";";
resp += ds + "GC" + c + useGammaCorrectionRGB +";";
resp += ds + "TF" + c + fadeTransition +";";
resp += ds + "TS" + c + sweepTransition +";";
resp += ds + "TI" + c + !sweepDirection +";";
resp += ds + "TD" + v + transitionDelay +";";
resp += ds + "BF" + v + briMultiplier +";";
resp += ds + "TB" + v + nightlightTargetBri +";";
resp += ds + "TL" + v + nightlightDelayMins +";";
resp += ds + "TW" + c + nightlightFade +";";
resp += ds + "RV" + c + reverseMode +";";
resp += ds + "EI" + c + initLedsLast +";";
resp += ds + "WO" + v + arlsOffset +";";
sappend('v',"LC",ledCount);
sappend('v',"CR",colS[0]);
sappend('v',"CG",colS[1]);
sappend('v',"CB",colS[2]);
sappend('v',"CA",briS);
sappend('c',"EW",useRGBW);
sappend('c',"AW",autoRGBtoRGBW);
sappend('v',"CW",whiteS);
sappend('v',"SR",colSecS[0]);
sappend('v',"SG",colSecS[1]);
sappend('v',"SB",colSecS[2]);
sappend('v',"SW",whiteSecS);
sappend('c',"BO",turnOnAtBoot);
sappend('v',"BP",bootPreset);
sappend('v',"FX",effectDefault);
sappend('v',"SX",effectSpeedDefault);
sappend('v',"IX",effectIntensityDefault);
sappend('c',"GB",useGammaCorrectionBri);
sappend('c',"GC",useGammaCorrectionRGB);
sappend('c',"TF",fadeTransition);
sappend('c',"TS",sweepTransition);
sappend('c',"TI",!sweepDirection);
sappend('v',"TD",transitionDelay);
sappend('c',"T2",!disableSecTransition);
sappend('v',"BF",briMultiplier);
sappend('v',"TB",nightlightTargetBri);
sappend('v',"TL",nightlightDelayMins);
sappend('c',"TW",nightlightFade);
sappend('c',"RV",reverseMode);
sappend('c',"EI",initLedsLast);
sappend('c',"SL",skipFirstLed);
}
if (subPage == 3)
{
resp += ds + "DS" + v + "\"" + serverDescription + "\";";
resp += ds + "MD" + c + useHSBDefault + ";";
resp += ds + "TH" + si + String(currentTheme) + ";";
for(int i=0;i<6;i++)
resp += ds + "C" + i + v + "\"" + cssCol[i] + "\";";
resp += ds + "CF" + v + "\"" + cssFont + "\";";
sappend('i',"UI",uiConfiguration);
sappends('s',"DS",serverDescription);
sappend('c',"MD",useHSBDefault);
sappend('i',"TH",currentTheme);
char k[3]; k[0] = 'C'; k[2] = 0; //keys
for (int i=0; i<6; i++)
{
k[1] = 48+i; //ascii 0,1,2,3,4,5
sappends('s',k,cssCol[i]);
}
sappends('s',"CF",cssFont);
}
if (subPage == 4)
{
resp += ds + "BT" + c + buttonEnabled +";";
resp += ds + "UP" + v + udpPort +";";
resp += ds + "RB" + c + receiveNotificationBrightness +";";
resp += ds + "RC" + c + receiveNotificationColor +";";
resp += ds + "RX" + c + receiveNotificationEffects +";";
resp += ds + "SD" + c + notifyDirectDefault +";";
resp += ds + "SB" + c + notifyButton +";";
resp += ds + "SH" + c + notifyHue +";";
resp += ds + "S2" + c + notifyTwice +";";
resp += ds + "AL" + c + alexaEnabled +";";
resp += ds + "AI" + v + "\"" + alexaInvocationName + "\";";
resp += ds + "SA" + c + alexaNotify +";";
resp += ds + "H0" + v + hueIP[0] +";";
resp += ds + "H1" + v + hueIP[1] +";";
resp += ds + "H2" + v + hueIP[2] +";";
resp += ds + "H3" + v + hueIP[3] +";";
resp += ds + "HL" + v + huePollLightId +";";
resp += ds + "HI" + v + huePollIntervalMs +";";
resp += ds + "HP" + c + huePollingEnabled +";";
resp += ds + "HO" + c + hueApplyOnOff +";";
resp += ds + "HB" + c + hueApplyBri +";";
resp += ds + "HC" + c + hueApplyColor +";";
resp += dg + "(\"hms\")[0]" + ih + "\"" + hueError + "\";";
sappend('c',"BT",buttonEnabled);
sappend('v',"UP",udpPort);
sappend('c',"RB",receiveNotificationBrightness);
sappend('c',"RC",receiveNotificationColor);
sappend('c',"RX",receiveNotificationEffects);
sappend('c',"SD",notifyDirectDefault);
sappend('c',"SB",notifyButton);
sappend('c',"SH",notifyHue);
sappend('c',"S2",notifyTwice);
sappend('c',"RD",receiveDirect);
sappend('c',"EM",e131Multicast);
sappend('v',"EU",e131Universe);
sappend('v',"ET",arlsTimeoutMillis);
sappend('c',"FB",arlsForceMaxBri);
sappend('c',"RG",arlsDisableGammaCorrection);
sappend('v',"WO",arlsOffset);
sappend('c',"RU",enableRealtimeUI);
sappend('c',"AL",alexaEnabled);
sappends('s',"AI",alexaInvocationName);
sappend('c',"SA",alexaNotify);
sappends('s',"BK",(char*)((blynkEnabled)?"Hidden":""));
sappend('v',"H0",hueIP[0]);
sappend('v',"H1",hueIP[1]);
sappend('v',"H2",hueIP[2]);
sappend('v',"H3",hueIP[3]);
sappend('v',"HL",huePollLightId);
sappend('v',"HI",huePollIntervalMs);
sappend('c',"HP",huePollingEnabled);
sappend('c',"HO",hueApplyOnOff);
sappend('c',"HB",hueApplyBri);
sappend('c',"HC",hueApplyColor);
sappends('m',"(\"hms\")[0]",hueError);
}
if (subPage == 5)
{
resp += ds + "NT" + c + ntpEnabled +";";
resp += ds + "CF" + c + !useAMPM +";";
resp += ds + "TZ" + si + String(currentTimezone) + ";";
resp += ds + "UO" + v + utcOffsetSecs +";";
resp += dg + "(\"times\")[0]" + ih + "\"" + getTimeString() + "\";";
resp += ds + "OL" + si + String(overlayCurrent) + ";";
resp += ds + "O1" + v + overlayMin +";";
resp += ds + "O2" + v + overlayMax +";";
resp += ds + "OM" + v + analogClock12pixel +";";
resp += ds + "OS" + c + analogClockSecondsTrail +";";
resp += ds + "O5" + c + analogClock5MinuteMarks +";";
resp += ds + "CX" + v + "\"" + cronixieDisplay + "\";";
resp += ds + "CB" + c + cronixieBacklight +";";
resp += ds + "CE" + c + countdownMode +";";
resp += ds + "CY" + v + countdownYear +";";
resp += ds + "CI" + v + countdownMonth +";";
resp += ds + "CD" + v + countdownDay +";";
resp += ds + "CH" + v + countdownHour +";";
resp += ds + "CM" + v + countdownMin +";";
resp += ds + "CS" + v + countdownSec +";";
sappend('c',"NT",ntpEnabled);
sappend('c',"CF",!useAMPM);
sappend('i',"TZ",currentTimezone);
sappend('v',"UO",utcOffsetSecs);
sappends('m',"(\"times\")[0]",(char*)getTimeString().c_str());
sappend('i',"OL",overlayCurrent);
sappend('v',"O1",overlayMin);
sappend('v',"O2",overlayMax);
sappend('v',"OM",analogClock12pixel);
sappend('c',"OS",analogClockSecondsTrail);
sappend('c',"O5",analogClock5MinuteMarks);
sappends('s',"CX",cronixieDisplay);
sappend('c',"CB",cronixieBacklight);
sappend('c',"CE",countdownMode);
sappend('v',"CY",countdownYear);
sappend('v',"CI",countdownMonth);
sappend('v',"CD",countdownDay);
sappend('v',"CH",countdownHour);
sappend('v',"CM",countdownMin);
sappend('v',"CS",countdownSec);
char k[4]; k[0]= 'M';
for (int i=1;i<17;i++)
{
resp += ds + "M" + String(i) + v + "\"" + loadMacro(i) + "\";";
sprintf(k+1,"%i",i);
sappends('s',k,(char*)loadMacro(i).c_str());
}
resp += ds + "MB" + v + macroBoot +";";
resp += ds + "A0" + v + macroAlexaOn +";";
resp += ds + "A1" + v + macroAlexaOff +";";
resp += ds + "MP" + v + macroButton +";";
resp += ds + "ML" + v + macroLongPress +";";
resp += ds + "MC" + v + macroCountdown +";";
resp += ds + "MN" + v + macroNl +";";
sappend('v',"MB",macroBoot);
sappend('v',"A0",macroAlexaOn);
sappend('v',"A1",macroAlexaOff);
sappend('v',"MP",macroButton);
sappend('v',"ML",macroLongPress);
sappend('v',"MC",macroCountdown);
sappend('v',"MN",macroNl);
}
if (subPage == 6)
{
resp += ds + "NO" + c + otaLock +";";
resp += ds + "OW" + c + wifiLock +";";
resp += ds + "AO" + c + aOtaEnabled +";";
resp += ds + "NA" + c + recoveryAPDisabled +";";
resp += dg + "(\"msg\")[0]" + ih + "\"WLED "+ versionString +" (build " + VERSION + ") OK\";";
sappend('c',"NO",otaLock);
sappend('c',"OW",wifiLock);
sappend('c',"AO",aOtaEnabled);
sappend('c',"NA",recoveryAPDisabled);
sappends('m',"(\"msg\")[0]","WLED ");
olen -= 2; //delete ";
oappend(versionString);
oappend(" (build ");
oappendi(VERSION);
oappend(") OK\";");
}
resp += "}</script>";
return resp;
oappend("}</script>");
}

View File

@@ -21,91 +21,44 @@ void handleSettingsSet(byte subPage)
//WIFI SETTINGS
if (subPage == 1)
{
if (server.hasArg("CS")) clientSSID = server.arg("CS");
if (server.hasArg("CS")) strcpy(clientSSID,server.arg("CS").c_str());
if (server.hasArg("CP"))
{
if (!server.arg("CP").indexOf('*') == 0)
{
DEBUG_PRINTLN("Setting pass");
clientPass = server.arg("CP");
strcpy(clientPass,server.arg("CP").c_str());
}
}
if (server.hasArg("CM")) cmDNS = server.arg("CM");
if (server.hasArg("CM")) strcpy(cmDNS,server.arg("CM").c_str());
if (server.hasArg("AT"))
{
int i = server.arg("AT").toInt();
if (i >= 0 && i <= 255) apWaitTimeSecs = i;
}
if (server.hasArg("AS")) apSSID = server.arg("AS");
if (server.hasArg("AS")) strcpy(apSSID,server.arg("AS").c_str());
apHide = server.hasArg("AH");
if (server.hasArg("AP"))
{
if (!server.arg("AP").indexOf('*') == 0) apPass = server.arg("AP");
if (server.arg("AP").charAt(0) != '*') strcpy(apPass,server.arg("AP").c_str());
}
if (server.hasArg("AC"))
{
int chan = server.arg("AC").toInt();
if (chan > 0 && chan < 14) apChannel = chan;
}
if (server.hasArg("I0"))
char k[3]; k[2] = 0; int j = 0;
for (int i = 0; i<4; i++)
{
int i = server.arg("I0").toInt();
if (i >= 0 && i <= 255) staticIP[0] = i;
}
if (server.hasArg("I1"))
{
int i = server.arg("I1").toInt();
if (i >= 0 && i <= 255) staticIP[1] = i;
}
if (server.hasArg("I2"))
{
int i = server.arg("I2").toInt();
if (i >= 0 && i <= 255) staticIP[2] = i;
}
if (server.hasArg("I3"))
{
int i = server.arg("I3").toInt();
if (i >= 0 && i <= 255) staticIP[3] = i;
}
if (server.hasArg("G0"))
{
int i = server.arg("G0").toInt();
if (i >= 0 && i <= 255) staticGateway[0] = i;
}
if (server.hasArg("G1"))
{
int i = server.arg("G1").toInt();
if (i >= 0 && i <= 255) staticGateway[1] = i;
}
if (server.hasArg("G2"))
{
int i = server.arg("G2").toInt();
if (i >= 0 && i <= 255) staticGateway[2] = i;
}
if (server.hasArg("G3"))
{
int i = server.arg("G3").toInt();
if (i >= 0 && i <= 255) staticGateway[3] = i;
}
if (server.hasArg("S0"))
{
int i = server.arg("S0").toInt();
if (i >= 0 && i <= 255) staticSubnet[0] = i;
}
if (server.hasArg("S1"))
{
int i = server.arg("S1").toInt();
if (i >= 0 && i <= 255) staticSubnet[1] = i;
}
if (server.hasArg("S2"))
{
int i = server.arg("S2").toInt();
if (i >= 0 && i <= 255) staticSubnet[2] = i;
}
if (server.hasArg("S3"))
{
int i = server.arg("S3").toInt();
if (i >= 0 && i <= 255) staticSubnet[3] = i;
k[1] = i+48;
k[0] = 'I'; //static IP
if (server.hasArg(k)) j = server.arg(k).toInt();
if (j >= 0 && j <= 255) staticIP[i] = j;
k[0] = 'G'; //gateway
if (server.hasArg(k)) j = server.arg(k).toInt();
if (j >= 0 && j <= 255) staticGateway[i] = j;
k[0] = 'S'; //subnet
if (server.hasArg(k)) j = server.arg(k).toInt();
if (j >= 0 && j <= 255) staticSubnet[i] = j;
}
}
@@ -115,9 +68,15 @@ void handleSettingsSet(byte subPage)
if (server.hasArg("LC"))
{
int i = server.arg("LC").toInt();
if (i >= 0 && i <= LEDCOUNT) ledCount = i;
strip.setLedCount(ledCount);
if (i > 0 && i <= 1200) ledCount = i;
//RMT eats up too much RAM
#ifdef ARDUINO_ARCH_ESP32
if (ledCount > 600) ledCount = 600;
#endif
}
ccIndex2 = ledCount -1;
useRGBW = server.hasArg("EW");
autoRGBtoRGBW = server.hasArg("AW");
if (server.hasArg("IS")) //ignore settings and save current brightness, colors and fx as default
{
colS[0] = col[0];
@@ -166,14 +125,7 @@ void handleSettingsSet(byte subPage)
if (server.hasArg("CW"))
{
int i = server.arg("CW").toInt();
if (i >= 0 && i <= 255)
{
useRGBW = true;
whiteS = i;
} else {
useRGBW = false;
whiteS = 0;
}
if (i >= 0 && i <= 255) whiteS = i;
}
if (server.hasArg("CA"))
{
@@ -196,6 +148,7 @@ void handleSettingsSet(byte subPage)
if (i >= 0 && i <= 255) effectIntensityDefault = i;
}
}
saveCurrPresetCycConf = server.hasArg("PC");
turnOnAtBoot = server.hasArg("BO");
if (server.hasArg("BP"))
{
@@ -214,6 +167,7 @@ void handleSettingsSet(byte subPage)
transitionDelay = i;
}
}
disableSecTransition = !server.hasArg("T2");
if (server.hasArg("TB"))
{
nightlightTargetBri = server.arg("TB").toInt();
@@ -227,11 +181,7 @@ void handleSettingsSet(byte subPage)
reverseMode = server.hasArg("RV");
initLedsLast = server.hasArg("EI");
strip.setReverseMode(reverseMode);
if (server.hasArg("WO"))
{
int i = server.arg("WO").toInt();
if (i >= -255 && i <= 255) arlsOffset = i;
}
skipFirstLed = server.hasArg("SL");
if (server.hasArg("BF"))
{
int i = server.arg("BF").toInt();
@@ -242,15 +192,18 @@ void handleSettingsSet(byte subPage)
//UI
if (subPage == 3)
{
if (server.hasArg("DS")) serverDescription = server.arg("DS");
if (server.hasArg("UI")) uiConfiguration = server.arg("UI").toInt();
if (server.hasArg("DS")) strcpy(serverDescription,server.arg("DS").c_str());
useHSBDefault = server.hasArg("MD");
useHSB = useHSBDefault;
if (server.hasArg("TH")) currentTheme = server.arg("TH").toInt();
char k[3]; k[0]='C'; k[2]=0;
for(int i=0;i<6;i++)
{
if (server.hasArg("C"+String(i))) cssCol[i] = server.arg("C"+String(i));
k[1] = i+48;
if (server.hasArg(k)) strcpy(cssCol[i],server.arg(k).c_str());
}
if (server.hasArg("CF")) cssFont = server.arg("CF");
if (server.hasArg("CF")) strcpy(cssFont,server.arg("CF").c_str());
buildCssColorString();
}
@@ -270,9 +223,29 @@ void handleSettingsSet(byte subPage)
notifyDirect = notifyDirectDefault;
notifyButton = server.hasArg("SB");
notifyTwice = server.hasArg("S2");
receiveDirect = server.hasArg("RD");
if (server.hasArg("EU"))
{
int i = server.arg("EU").toInt();
if (i > 0 && i <= 63999) arlsTimeoutMillis = i;
}
if (server.hasArg("ET"))
{
int i = server.arg("ET").toInt();
if (i > 99 && i <= 65000) arlsTimeoutMillis = i;
}
arlsForceMaxBri = server.hasArg("FB");
arlsDisableGammaCorrection = server.hasArg("RG");
if (server.hasArg("WO"))
{
int i = server.arg("WO").toInt();
if (i >= -255 && i <= 255) arlsOffset = i;
}
enableRealtimeUI = server.hasArg("RU");
alexaEnabled = server.hasArg("AL");
if (server.hasArg("AI")) alexaInvocationName = server.arg("AI");
if (server.hasArg("AI")) strcpy(alexaInvocationName,server.arg("AI").c_str());
alexaNotify = server.hasArg("SA");
if (server.hasArg("BK") && !server.arg("BK").equals("Hidden")) {strcpy(blynkApiKey,server.arg("BK").c_str()); initBlynk(blynkApiKey);}
notifyHue = server.hasArg("SH");
for (int i=0;i<4;i++){
String a = "H"+String(i);
@@ -299,7 +272,7 @@ void handleSettingsSet(byte subPage)
} else
{
huePollingEnabled = false;
hueError = "Inactive";
strcpy(hueError,"Inactive");
}
}
@@ -323,7 +296,7 @@ void handleSettingsSet(byte subPage)
analogClock5MinuteMarks = server.hasArg("O5");
analogClockSecondsTrail = server.hasArg("OS");
if (server.hasArg("CX")) cronixieDisplay = server.arg("CX");
if (server.hasArg("CX")) strcpy(cronixieDisplay,server.arg("CX").c_str());
bool cbOld = cronixieBacklight;
cronixieBacklight = server.hasArg("CB");
if (cbOld != cronixieBacklight && overlayCurrent == 4)
@@ -365,13 +338,13 @@ void handleSettingsSet(byte subPage)
bool pwdCorrect = !otaLock; //always allow access if ota not locked
if (server.hasArg("OP"))
{
if (otaLock && otaPass.equals(server.arg("OP")))
if (otaLock && strcmp(otaPass,server.arg("OP").c_str()) == 0)
{
pwdCorrect = true;
}
if (!otaLock && server.arg("OP").length() > 0)
{
otaPass = server.arg("OP");
strcpy(otaPass,server.arg("OP").c_str());
}
}
@@ -383,8 +356,8 @@ void handleSettingsSet(byte subPage)
aOtaEnabled = server.hasArg("AO");
}
}
saveSettingsToEEPROM();
if (subPage == 2) strip.init(useRGBW,ledCount,PIN,skipFirstLed);
}
bool handleSet(String req)
@@ -642,6 +615,8 @@ bool handleSet(String req)
}
}
//toggle nightlight mode
bool aNlDef = false;
if (req.indexOf("&ND") > 0) aNlDef = true;
pos = req.indexOf("NL=");
if (pos > 0)
{
@@ -651,9 +626,13 @@ bool handleSet(String req)
bri = briT;
} else {
nightlightActive = true;
nightlightDelayMins = req.substring(pos + 3).toInt();
if (!aNlDef) nightlightDelayMins = req.substring(pos + 3).toInt();
nightlightStartTime = millis();
}
} else if (aNlDef)
{
nightlightActive = true;
nightlightStartTime = millis();
}
//set nightlight target brightness
pos = req.indexOf("NT=");
@@ -679,6 +658,10 @@ bool handleSet(String req)
auxActive = true;
if (auxTime == 0) auxActive = false;
}
pos = req.indexOf("TT=");
if (pos > 0) {
transitionDelay = req.substring(pos + 3).toInt();
}
//main toggle on/off
pos = req.indexOf("&T=");
if (pos > 0) {
@@ -696,6 +679,8 @@ bool handleSet(String req)
}
}
}
//deactivate nightlight if target brightness is reached
if (bri == nightlightTargetBri) nightlightActive = false;
//set time (unix timestamp)
pos = req.indexOf("ST=");
if (pos > 0) {
@@ -718,36 +703,59 @@ bool handleSet(String req)
pos = req.indexOf("CM="); if (pos > 0) {ccStep = (req.substring(pos + 3).toInt()); _cc_updated = true;}
pos = req.indexOf("CF="); if (pos > 0) {ccFromStart = (req.substring(pos + 3).toInt()); _cc_updated = true;}
pos = req.indexOf("CE="); if (pos > 0) {ccFromEnd = (req.substring(pos + 3).toInt()); _cc_updated = true;}
if (ccIndex2 == 255) ccIndex2 = ledCount-1;
if (_cc_updated) strip.setCustomChase(ccIndex1, ccIndex2, ccStart, ccNumPrimary, ccNumSecondary, ccStep, ccFromStart, ccFromEnd);
//set presets
pos = req.indexOf("P1="); //sets first preset for cycle
if (pos > 0) presetCycleMin = req.substring(pos + 3).toInt();
pos = req.indexOf("P2="); //sets last preset for cycle
if (pos > 0) presetCycleMax = req.substring(pos + 3).toInt();
if (req.indexOf("CY=") > 0) //preset cycle
{
presetCyclingEnabled = true;
if (req.indexOf("CY=0") > 0)
{
presetCyclingEnabled = false;
}
presetCycCurr = presetCycleMin;
}
pos = req.indexOf("PT="); //sets cycle time in ms
if (pos > 0) {
int v = req.substring(pos + 3).toInt();
if (v > 49) presetCycleTime = v;
}
if (req.indexOf("PA=") > 0) //apply brightness from preset
{
presetApplyBri = true;
if (req.indexOf("PA=0") > 0) presetApplyBri = false;
}
if (req.indexOf("PC=") > 0) //apply color from preset
{
presetApplyCol = true;
if (req.indexOf("PC=0") > 0) presetApplyCol = false;
}
if (req.indexOf("PX=") > 0) //apply effects from preset
{
presetApplyFx = true;
if (req.indexOf("PX=0") > 0) presetApplyFx = false;
}
pos = req.indexOf("PS="); //saves current in preset
if (pos > 0) {
savePreset(req.substring(pos + 3).toInt());
}
pos = req.indexOf("PL="); //applies entire preset
if (pos > 0) {
applyPreset(req.substring(pos + 3).toInt(), true, true, true);
effectUpdated = true;
}
pos = req.indexOf("PA="); //applies brightness from preset
if (pos > 0) {
applyPreset(req.substring(pos + 3).toInt(), true, false, false);
}
pos = req.indexOf("PC="); //applies color from preset
if (pos > 0) {
applyPreset(req.substring(pos + 3).toInt(), false, true, false);
}
pos = req.indexOf("PX="); //applies effects from preset
if (pos > 0) {
applyPreset(req.substring(pos + 3).toInt(), false, false, true);
effectUpdated = true;
applyPreset(req.substring(pos + 3).toInt(), presetApplyBri, presetApplyCol, presetApplyFx);
if (presetApplyFx) effectUpdated = true;
}
//cronixie
pos = req.indexOf("NX="); //sets digits to code
if (pos > 0) {
cronixieDisplay = req.substring(pos + 3, pos + 9);
strcpy(cronixieDisplay,req.substring(pos + 3, pos + 9).c_str());
setCronixie();
}
pos = req.indexOf("NM="); //mode, 1 countdown
@@ -768,7 +776,16 @@ bool handleSet(String req)
if (overlayCurrent == 4) strip.setCronixieBacklight(cronixieBacklight);
overlayRefreshedTime = 0;
}
pos = req.indexOf("U0="); //user var 0
if (pos > 0) {
userVar0 = req.substring(pos + 3).toInt();
}
pos = req.indexOf("U1="); //user var 1
if (pos > 0) {
userVar1 = req.substring(pos + 3).toInt();
}
//you can add more if you need
//internal call, does not send XML response
pos = req.indexOf("IN");
if (pos < 1) XML_response();

View File

@@ -1,6 +1,45 @@
/*
* Utility for SPIFFS filesystem
* Utility for SPIFFS filesystem & Serial console
*/
void handleSerial()
{
if (Serial.available() > 0) //support for Adalight protocol to high-speed control LEDs over serial (gamma correction done by PC)
{
if (Serial.find("Ada"))
{
if (!arlsTimeout){
if (bri == 0) strip.setBrightness(briLast);
strip.setRange(0, ledCount-1, 0);
strip.setMode(0);
}
arlsLock(arlsTimeoutMillis);
delay(1);
byte hi = Serial.read();
byte ledc = Serial.read();
byte chk = Serial.read();
if(chk != (hi ^ ledc ^ 0x55)) return;
if (ledCount < ledc) ledc = ledCount;
byte sc[3]; int t =-1; int to = 0;
for (int i=0; i < ledc; i++)
{
for (byte j=0; j<3; j++)
{
while (Serial.peek()<0) //no data yet available
{
delay(1);
to++;
if (to>5) {strip.show(); return;} //unexpected end of transmission
}
to = 0;
sc[j] = Serial.read();
}
setRealtimePixel(i,sc[0],sc[1],sc[2],0);
}
strip.show();
}
}
}
#ifdef USEFS
String formatBytes(size_t bytes){

View File

@@ -3,11 +3,18 @@
*/
void wledInit()
{
{
EEPROM.begin(EEPSIZE);
if (!EEPROM.read(397)) strip.init(); //quick init
showWelcomePage = (EEPROM.read(233) != 233);
ledCount = ((EEPROM.read(229) << 0) & 0xFF) + ((EEPROM.read(398) << 8) & 0xFF00); if (ledCount > 1200 || ledCount == 0) ledCount = 10;
//RMT eats up too much RAM
#ifdef ARDUINO_ARCH_ESP32
if (ledCount > 600) ledCount = 600;
#endif
if (!EEPROM.read(397)) strip.init(EEPROM.read(372),ledCount,PIN,EEPROM.read(2204)); //quick init
Serial.begin(115200);
Serial.setTimeout(50);
#ifdef USEFS
SPIFFS.begin();
@@ -16,32 +23,11 @@ void wledInit()
DEBUG_PRINTLN("Load EEPROM");
loadSettingsFromEEPROM(true);
if (!initLedsLast) initStrip();
DEBUG_PRINT("C-SSID: ");
DEBUG_PRINT("CSSID: ");
DEBUG_PRINT(clientSSID);
buildCssColorString();
userBeginPreConnection();
WiFi.disconnect(); //close old connections
if (staticIP[0] != 0)
{
WiFi.config(staticIP, staticGateway, staticSubnet, staticDNS);
} else
{
WiFi.config(0U, 0U, 0U);
}
if (apSSID.length()>0)
{
DEBUG_PRINT("USING AP");
DEBUG_PRINTLN(apSSID.length());
initAP();
} else
{
DEBUG_PRINTLN("NO AP");
WiFi.softAPdisconnect(true);
}
initCon();
DEBUG_PRINTLN("");
@@ -54,29 +40,23 @@ void wledInit()
hueIP[1] = WiFi.localIP()[1];
hueIP[2] = WiFi.localIP()[2];
}
// Set up mDNS responder:
if (cmDNS != NULL && !onlyAP && !MDNS.begin(cmDNS.c_str())) {
DEBUG_PRINTLN("Error setting up MDNS responder!");
down();
}
DEBUG_PRINTLN("mDNS responder started");
if (udpPort > 0 && udpPort != ntpLocalPort && WiFi.status() == WL_CONNECTED)
if (udpPort > 0 && udpPort != ntpLocalPort)
{
udpConnected = notifierUdp.begin(udpPort);
if (udpConnected && udpRgbPort != udpPort) udpRgbConnected = rgbUdp.begin(udpRgbPort);
}
if (ntpEnabled && WiFi.status() == WL_CONNECTED)
ntpConnected = ntpUdp.begin(ntpLocalPort);
//start captive portal
if (onlyAP || apSSID.length() > 0)
if (onlyAP || strlen(apSSID) > 0)
{
dnsServer.setErrorReplyCode(DNSReplyCode::NoError);
dnsServer.start(53, "*", WiFi.softAPIP());
dnsActive = true;
}
if (!initLedsLast) strip.service();
//SERVER INIT
//settings page
server.on("/settings", HTTP_GET, [](){
@@ -191,44 +171,20 @@ void wledInit()
val += "mA currently";
serveMessage(200,val,"This is just an estimate (does not take into account several factors like effects and wire resistance). It is NOT an accurate measurement!",254);
});
server.on("/u", HTTP_GET, [](){
server.setContentLength(strlen_P(PAGE_usermod));
server.send(200, "text/html", "");
server.sendContent_P(PAGE_usermod);
});
server.on("/teapot", HTTP_GET, [](){
serveMessage(418, "418. I'm a teapot.","(Tangible Embedded Advanced Project Of Twinkling)",254);
});
server.on("/build", HTTP_GET, [](){
String info = "hard-coded build info:\r\n\n";
#ifdef ARDUINO_ARCH_ESP32
info += "platform: esp32\r\n";
#else
info += "platform: esp8266\r\n";
#endif
info += "version: " + versionString + "\r\n";
info += "build: " + (String)VERSION + "\r\n";
info += "eepver: " + String(EEPVER) + "\r\n";
#ifdef RGBW
info += "rgbw: true\r\n";
#else
info += "rgbw: false\r\n";
#endif
info += "max-leds: " + (String)LEDCOUNT + "\r\n";
#ifdef USEFS
info += "spiffs: true\r\n";
#else
info += "spiffs: false\r\n";
#endif
#ifdef DEBUG
info += "debug: true\r\n";
#else
info += "debug: false\r\n";
#endif
info += "button-pin: gpio" + String(buttonPin) + "\r\n";
#ifdef ARDUINO_ARCH_ESP32
info += "strip-pin: gpio" + String(PIN) + "\r\n";
#else
info += "strip-pin: gpio2\r\n";
#endif
server.send(200, "text/plain", info);
getBuildInfo();
server.send(200, "text/plain", obuf);
});
//if OTA is allowed
if (!otaLock){
@@ -241,8 +197,6 @@ void wledInit()
server.on("/edit", HTTP_POST, [](){ server.send(200, "text/plain", ""); }, handleFileUpload);
server.on("/list", HTTP_GET, handleFileList);
#endif
server.on("/down", HTTP_GET, down);
server.on("/cleareeprom", HTTP_GET, clearEEPROM);
//init ota page
httpUpdater.setup(&server);
} else
@@ -250,12 +204,6 @@ void wledInit()
server.on("/edit", HTTP_GET, [](){
serveMessage(500, "Access Denied", txd, 254);
});
server.on("/down", HTTP_GET, [](){
serveMessage(500, "Access Denied", txd, 254);
});
server.on("/cleareeprom", HTTP_GET, [](){
serveMessage(500, "Access Denied", txd, 254);
});
server.on("/update", HTTP_GET, [](){
serveMessage(500, "Access Denied", txd, 254);
});
@@ -273,13 +221,21 @@ void wledInit()
server.send(404, "text/plain", "Not Found");
}
});
#ifndef ARDUINO_ARCH_ESP32
const char * headerkeys[] = {"User-Agent"};
server.collectHeaders(headerkeys,sizeof(headerkeys)/sizeof(char*));
#else
String ua = "User-Agent";
server.collectHeaders(ua);
#endif
if (!initLedsLast) strip.service();
//init Alexa hue emulation
if (alexaEnabled) alexaInit();
server.begin();
DEBUG_PRINTLN("HTTP server started");
// Add service to MDNS
MDNS.addService("http", "tcp", 80);
//init ArduinoOTA
if (aOtaEnabled)
@@ -290,25 +246,42 @@ void wledInit()
#endif
DEBUG_PRINTLN("Start ArduinoOTA");
});
if (strlen(cmDNS) > 0) ArduinoOTA.setHostname(cmDNS);
ArduinoOTA.begin();
}
if (!initLedsLast) strip.service();
// Set up mDNS responder:
if (strlen(cmDNS) > 0 && !onlyAP)
{
MDNS.begin(cmDNS);
DEBUG_PRINTLN("mDNS responder started");
// Add service to MDNS
MDNS.addService("http", "tcp", 80);
}
initBlynk(blynkApiKey);
initE131();
if (initLedsLast) initStrip();
userBegin();
if (macroBoot>0) applyMacro(macroBoot);
Serial.println("Ada");
}
void initStrip()
{
// Initialize NeoPixel Strip and button
if (initLedsLast) strip.init();
strip.setLedCount(ledCount);
if (initLedsLast) strip.init(useRGBW,ledCount,PIN,skipFirstLed);
strip.setReverseMode(reverseMode);
strip.setColor(0);
strip.setBrightness(255);
strip.start();
pinMode(buttonPin, INPUT_PULLUP);
pinMode(4,OUTPUT); //this is only needed in special cases
digitalWrite(4,LOW);
if (bootPreset>0) applyPreset(bootPreset, turnOnAtBoot, true, true);
colorUpdated(0);
@@ -316,17 +289,43 @@ void initStrip()
}
void initAP(){
String save = apSSID;
if (apSSID.length() <1) apSSID = "WLED-AP";
WiFi.softAP(apSSID.c_str(), apPass.c_str(), apChannel, apHide);
apSSID = save;
bool set = apSSID[0];
if (!set) strcpy(apSSID,"WLED-AP");
WiFi.softAP(apSSID, apPass, apChannel, apHide);
if (!set) apSSID[0] = 0;
}
void initCon()
{
WiFi.disconnect(); //close old connections
if (staticIP[0] != 0)
{
WiFi.config(staticIP, staticGateway, staticSubnet, staticDNS);
} else
{
WiFi.config(0U, 0U, 0U);
}
if (strlen(apSSID)>0)
{
DEBUG_PRINT("USING AP");
DEBUG_PRINTLN(strlen(apSSID));
initAP();
} else
{
DEBUG_PRINTLN("NO AP");
WiFi.softAPdisconnect(true);
}
int fail_count = 0;
if (clientSSID.length() <1 || clientSSID.equals("Your_Network")) fail_count = apWaitTimeSecs*2;
WiFi.begin(clientSSID.c_str(), clientPass.c_str());
if (strlen(clientSSID) <1 || strcmp(clientSSID,"Your_Network") == 0) fail_count = apWaitTimeSecs*2; //instantly go to ap mode
#ifndef ARDUINO_ARCH_ESP32
WiFi.hostname(serverDescription);
#endif
WiFi.begin(clientSSID, clientPass);
#ifdef ARDUINO_ARCH_ESP32
WiFi.setHostname(serverDescription);
#endif
unsigned long lastTry = 0;
bool con = false;
while(!con)
@@ -341,7 +340,6 @@ void initCon()
}
if (millis()-lastTry > 499) {
con = (WiFi.status() == WL_CONNECTED);
if (con) DEBUG_PRINTLN("rofl");
lastTry = millis();
DEBUG_PRINTLN("C_NC");
if (!recoveryAPDisabled && fail_count > apWaitTimeSecs*2)
@@ -374,6 +372,7 @@ void buildCssColorString()
case 9: cs[0]="f70"; cs[1]="421"; cs[2]="221"; cs[3]="a50"; cs[4]="f70"; cs[5]="f70"; break;//nixie
case 10: cs[0]="2d2"; cs[1]="010"; cs[2]="121"; cs[3]="060"; cs[4]="040"; cs[5]="3f3"; break; //terminal
case 11: cs[0]="867ADE"; cs[1]="4033A3"; cs[2]="483AAA"; cs[3]="483AAA"; cs[4]=""; cs[5]="867ADE"; break; //c64
case 12: cs[0]="fbe8a6"; cs[1]="d2fdff"; cs[2]="b4dfe5"; cs[3]="f4976c"; cs[4]=""; cs[5]="303c6c"; break; //c64
case 14: cs[0]="fc7"; cs[1]="49274a"; cs[2]="94618e"; cs[3]="f4decb"; cs[4]="0008"; cs[5]="f4decb"; break; //end
case 15: for (int i=0;i<6;i++)cs[i]=cssCol[i];//custom
}
@@ -404,22 +403,56 @@ void serveIndexOrWelcome()
if(!handleFileRead("/welcome.htm")) {
serveSettings(255);
}
showWelcomePage = false;
}
}
void serveRealtimeError(bool settings)
{
String mesg = "The ";
mesg += (settings)?"settings":"WLED";
mesg += " UI is not available while receiving real-time data (";
if (realtimeIP[0] == 0)
{
mesg += "E1.31";
} else {
mesg += "UDP from ";
mesg += realtimeIP[0];
for (int i = 1; i < 4; i++)
{
mesg += ".";
mesg += realtimeIP[i];
}
}
mesg += ").";
server.send(200, "text/plain", mesg);
}
void serveIndex()
{
if (!arlsTimeout) //do not serve while receiving realtime
bool serveMobile = false;
if (uiConfiguration == 0) serveMobile = checkClientIsMobile(server.header("User-Agent"));
else if (uiConfiguration == 2) serveMobile = true;
if (!arlsTimeout || enableRealtimeUI) //do not serve while receiving realtime
{
server.setContentLength(strlen_P(PAGE_index0) + cssColorString.length() + strlen_P(PAGE_index1) + strlen_P(PAGE_index2) + strlen_P(PAGE_index3));
server.send(200, "text/html", "");
server.sendContent_P(PAGE_index0);
server.sendContent(cssColorString);
server.sendContent_P(PAGE_index1);
server.sendContent_P(PAGE_index2);
server.sendContent_P(PAGE_index3);
if (serveMobile)
{
server.setContentLength(strlen_P(PAGE_indexM));
server.send(200, "text/html", "");
server.sendContent_P(PAGE_indexM);
} else
{
server.setContentLength(strlen_P(PAGE_index0) + cssColorString.length() + strlen_P(PAGE_index1) + strlen_P(PAGE_index2) + strlen_P(PAGE_index3));
server.send(200, "text/html", "");
server.sendContent_P(PAGE_index0);
server.sendContent(cssColorString);
server.sendContent_P(PAGE_index1);
server.sendContent_P(PAGE_index2);
server.sendContent_P(PAGE_index3);
}
} else {
server.send(200, "text/plain", "The WLED UI is not available while receiving real-time data.");
serveRealtimeError(false);
}
}
@@ -457,7 +490,7 @@ void serveMessage(int code, String headl, String subl="", int optionType)
void serveSettings(byte subPage)
{
//0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec 255: welcomepage
if (!arlsTimeout) //do not serve while receiving realtime
if (!arlsTimeout || enableRealtimeUI) //do not serve while receiving realtime
{
int pl0, pl1;
switch (subPage)
@@ -472,10 +505,10 @@ void serveSettings(byte subPage)
default: pl0 = strlen_P(PAGE_settings0); pl1 = strlen_P(PAGE_settings1);
}
String settingsBuffer = getSettings(subPage);
getSettingsJS(subPage);
int sCssLength = (subPage >0 && subPage <7)?strlen_P(PAGE_settingsCss):0;
server.setContentLength(pl0 + cssColorString.length() + settingsBuffer.length() + sCssLength + pl1);
server.setContentLength(pl0 + cssColorString.length() + olen + sCssLength + pl1);
server.send(200, "text/html", "");
switch (subPage)
@@ -489,7 +522,7 @@ void serveSettings(byte subPage)
case 255: server.sendContent_P(PAGE_welcome0); break;
default: server.sendContent_P(PAGE_settings0);
}
server.sendContent(settingsBuffer);
server.sendContent(obuf);
server.sendContent(cssColorString);
if (subPage >0 && subPage <7) server.sendContent_P(PAGE_settingsCss);
switch (subPage)
@@ -504,10 +537,56 @@ void serveSettings(byte subPage)
default: server.sendContent_P(PAGE_settings1);
}
} else {
server.send(200, "text/plain", "The settings are not available while receiving real-time data.");
serveRealtimeError(true);
}
}
void getBuildInfo()
{
//fill string buffer with build info
olen = 0;
oappend("hard-coded build info:\r\n\n");
#ifdef ARDUINO_ARCH_ESP32
oappend("platform: esp32");
#else
oappend("platform: esp8266");
#endif
oappend("\r\nversion: ");
oappend(versionString);
oappend("\r\nbuild: ");
oappendi(VERSION);
oappend("\r\neepver: ");
oappendi(EEPVER);
#ifdef USEFS
oappend("\r\nspiffs: true\r\n");
#else
oappend("\r\nspiffs: false\r\n");
#endif
#ifdef DEBUG
oappend("debug: true\r\n");
#else
oappend("debug: false\r\n");
#endif
oappend("button-pin: gpio");
oappendi(buttonPin);
oappend("\r\n");
#ifdef ARDUINO_ARCH_ESP32
oappend("strip-pin: gpio");
oappendi(PIN);
#else
oappend("strip-pin: gpio2");
#endif
oappend("\r\nbuild-type: src\r\n");
}
bool checkClientIsMobile(String useragent)
{
//to save complexity this function is not comprehensive
if (useragent.indexOf("Android") >= 0) return true;
if (useragent.indexOf("iPhone") >= 0) return true;
if (useragent.indexOf("iPod") >= 0) return true;
return false;
}

View File

@@ -4,9 +4,11 @@
* EEPROM bytes 2944 to 3071 are reserved for your custom use case.
*/
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
void userBeginPreConnection()
{
}
void userBegin()
@@ -18,4 +20,3 @@ void userLoop()
{
}

View File

@@ -9,11 +9,14 @@ void notify(byte callMode, bool followUp=false)
if (!udpConnected) return;
switch (callMode)
{
case 0: return;
case 1: if (!notifyDirect) return; break;
case 2: if (!notifyButton) return; break;
case 4: if (!notifyDirect) return; break;
case 6: if (!notifyDirect) return; break; //fx change
case 7: if (!notifyHue) return; break;
case 8: if (!notifyDirect) return; break;
case 9: if (!notifyDirect) return; break;
default: return;
}
byte udpOut[WLEDPACKETSIZE];
@@ -48,20 +51,88 @@ void notify(byte callMode, bool followUp=false)
notificationTwoRequired = (followUp)? false:notifyTwice;
}
void arlsLock(uint32_t timeoutMs)
{
if (!arlsTimeout){
strip.setRange(0, ledCount-1, 0);
strip.setMode(0);
}
arlsTimeout = true;
arlsTimeoutTime = millis() + timeoutMs;
if (arlsForceMaxBri) strip.setBrightness(255);
}
void initE131(){
if (WiFi.status() == WL_CONNECTED && e131Enabled)
{
e131.begin((e131Multicast) ? E131_MULTICAST : E131_UNICAST , e131Universe);
} else {
e131Enabled = false;
}
}
void handleNotifications()
{
//send second notification if enabled
if(udpConnected && notificationTwoRequired && millis()-notificationSentTime > 250){
notify(notificationSentCallMode,true);
}
if(udpConnected && receiveNotifications){
//E1.31 protocol support
if(e131Enabled) {
uint16_t len = e131.parsePacket();
if (len && e131.universe == e131Universe) {
arlsLock(arlsTimeoutMillis);
if (len > ledCount) len = ledCount;
for (uint16_t i = 0; i < len; i++) {
int j = i * 3;
setRealtimePixel(i, e131.data[j], e131.data[j+1], e131.data[j+2], 0);
}
strip.show();
}
}
//unlock strip when realtime UDP times out
if (arlsTimeout && millis() > arlsTimeoutTime)
{
strip.unlockAll();
strip.setBrightness(bri);
arlsTimeout = false;
strip.setMode(effectCurrent);
realtimeIP[0] = 0;
}
//receive UDP notifications
if(udpConnected && (receiveNotifications || receiveDirect)){
uint16_t packetSize = notifierUdp.parsePacket();
//hyperion / raw RGB
if (!packetSize && udpRgbConnected) {
packetSize = rgbUdp.parsePacket();
if (!receiveDirect) return;
realtimeIP = rgbUdp.remoteIP();
if (packetSize > 1026 || packetSize < 3) return;
byte udpIn[packetSize];
rgbUdp.read(udpIn, packetSize);
arlsLock(arlsTimeoutMillis);
uint16_t id = 0;
for (uint16_t i = 0; i < packetSize -2; i += 3)
{
setRealtimePixel(id, udpIn[i], udpIn[i+1], udpIn[i+2], 0);
id++; if (id >= ledCount) break;
}
strip.show();
return;
}
if (packetSize > 1026) return;
if(packetSize && notifierUdp.remoteIP() != WiFi.localIP()) //don't process broadcasts we send ourselves
{
byte udpIn[packetSize];
notifierUdp.read(udpIn, packetSize);
if (udpIn[0] == 0 && !arlsTimeout) //wled notifier, block if realtime packets active
if (udpIn[0] == 0 && !arlsTimeout && receiveNotifications) //wled notifier, block if realtime packets active
{
if (receiveNotificationColor)
{
@@ -105,39 +176,57 @@ void handleNotifications()
if (receiveNotificationBrightness) bri = udpIn[2];
colorUpdated(3);
}
} else if (udpIn[0] == 1) //warls
} else if (udpIn[0] > 0 && udpIn[0] < 4 && receiveDirect) //1 warls //2 drgb //3 drgbw
{
realtimeIP = notifierUdp.remoteIP();
if (packetSize > 1) {
if (udpIn[1] == 0)
{
arlsTimeout = false;
} else {
if (!arlsTimeout){
strip.setRange(0, ledCount-1, 0);
strip.setMode(0);
}
arlsTimeout = true;
arlsTimeoutTime = millis() + 1000*udpIn[1];
arlsLock(udpIn[1]*1000);
}
for (int i = 2; i < packetSize -3; i += 4)
if (udpIn[0] == 1) //warls
{
if (udpIn[i] + arlsOffset < ledCount && udpIn[i] + arlsOffset >= 0)
if (useGammaCorrectionRGB)
for (uint16_t i = 2; i < packetSize -3; i += 4)
{
strip.setPixelColor(udpIn[i] + arlsOffset, gamma8[udpIn[i+1]], gamma8[udpIn[i+2]], gamma8[udpIn[i+3]]);
} else {
strip.setPixelColor(udpIn[i] + arlsOffset, udpIn[i+1], udpIn[i+2], udpIn[i+3]);
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;
}
}
strip.show();
}
}
}
if (arlsTimeout && millis() > arlsTimeoutTime)
}
}
void setRealtimePixel(int i, byte r, byte g, byte b, byte w)
{
if (i + arlsOffset < ledCount && i + arlsOffset >= 0)
{
if (!arlsDisableGammaCorrection && useGammaCorrectionRGB)
{
strip.unlockAll();
arlsTimeout = false;
strip.setMode(effectCurrent);
strip.setPixelColor(i + arlsOffset, gamma8[r], gamma8[g], gamma8[b], gamma8[w]);
} else {
strip.setPixelColor(i + arlsOffset, r, g, b, w);
}
}
}

View File

@@ -3,37 +3,56 @@
*/
void setAllLeds() {
double d = briT*briMultiplier;
int val = d/100;
if (val > 255) val = 255;
if (useGammaCorrectionBri)
if (!arlsTimeout || !arlsForceMaxBri)
{
strip.setBrightness(gamma8[val]);
} else {
strip.setBrightness(val);
double d = briT*briMultiplier;
int val = d/100;
if (val > 255) val = 255;
if (useGammaCorrectionBri)
{
strip.setBrightness(gamma8[val]);
} else {
strip.setBrightness(val);
}
}
if (disableSecTransition)
{
for (byte i = 0; i<3; i++)
{
colSecT[i] = colSec[i];
}
whiteSecT = whiteSec;
}
if (autoRGBtoRGBW)
{
colorRGBtoRGBW(colT,&whiteT);
colorRGBtoRGBW(colSecT,&whiteSecT);
}
if (useGammaCorrectionRGB)
{
strip.setColor(gamma8[colT[0]], gamma8[colT[1]], gamma8[colT[2]], gamma8[whiteT]);
strip.setSecondaryColor(gamma8[colSec[0]], gamma8[colSec[1]], gamma8[colSec[2]], gamma8[whiteSec]);
strip.setSecondaryColor(gamma8[colSecT[0]], gamma8[colSecT[1]], gamma8[colSecT[2]], gamma8[whiteSecT]);
} else {
strip.setColor(colT[0], colT[1], colT[2], whiteT);
strip.setSecondaryColor(colSec[0], colSec[1], colSec[2], whiteSec);
strip.setSecondaryColor(colSecT[0], colSecT[1], colSecT[2], whiteSecT);
}
}
void setLedsStandard()
{
colOld[0] = col[0];
colOld[1] = col[1];
colOld[2] = col[2];
for (byte i = 0; i<3; i++)
{
colOld[i] = col[i];
colT[i] = col[i];
colSecOld[i] = colSec[i];
colSecT[i] = colSec[i];
}
whiteOld = white;
briOld = bri;
colT[0] = col[0];
colT[1] = col[1];
colT[2] = col[2];
whiteSecOld = whiteSec;
whiteT = white;
briT = bri;
whiteSecT = whiteSec;
setAllLeds();
}
@@ -51,7 +70,7 @@ bool colorChanged()
void colorUpdated(int callMode)
{
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (NN)6: fx changed 7: hue
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (NN)6: fx changed 7: hue 8: preset cycle 9: blynk
if (!colorChanged())
{
if (callMode == 6) notify(6);
@@ -78,6 +97,7 @@ void colorUpdated(int callMode)
{
//set correct delay if not using notification delay
if (callMode != 3) transitionDelayTemp = transitionDelay;
if (transitionDelayTemp == 0) {setLedsStandard();strip.trigger();return;}
if (transitionActive)
{
@@ -85,6 +105,10 @@ void colorUpdated(int callMode)
colOld[1] = colT[1];
colOld[2] = colT[2];
whiteOld = whiteT;
colSecOld[0] = colSecT[0];
colSecOld[1] = colSecT[1];
colSecOld[2] = colSecT[2];
whiteSecOld = whiteSecT;
briOld = briT;
tperLast = 0;
}
@@ -96,6 +120,7 @@ void colorUpdated(int callMode)
setLedsStandard();
strip.trigger();
}
if (callMode != 9 && callMode != 5 && callMode != 8) updateBlynk();
}
void handleTransitions()
@@ -112,17 +137,20 @@ void handleTransitions()
strip.setFastUpdateMode(false);
return;
}
if (tper - tperLast < transitionResolution)
if (tper - tperLast < 0.004)
{
return;
}
tperLast = tper;
if (fadeTransition)
{
colT[0] = colOld[0]+((col[0] - colOld[0])*tper);
colT[1] = colOld[1]+((col[1] - colOld[1])*tper);
colT[2] = colOld[2]+((col[2] - colOld[2])*tper);
for (byte i = 0; i<3; i++)
{
colT[i] = colOld[i]+((col[i] - colOld[i])*tper);
colSecT[i] = colSecOld[i]+((colSec[i] - colSecOld[i])*tper);
}
whiteT = whiteOld +((white - whiteOld )*tper);
whiteSecT = whiteSecOld +((whiteSec - whiteSecOld )*tper);
briT = briOld +((bri - briOld )*tper);
}
if (sweepTransition)
@@ -170,10 +198,21 @@ void handleNightlight()
bri = nightlightTargetBri;
colorUpdated(5);
}
updateBlynk();
if (bri == 0) briLast = briNlT;
}
} else if (nightlightActiveOld) //early de-init
{
nightlightActiveOld = false;
}
//also handle preset cycle here
if (presetCyclingEnabled && (millis() - presetCycledTime > presetCycleTime))
{
applyPreset(presetCycCurr,presetApplyBri,presetApplyCol,presetApplyFx);
presetCycCurr++; if (presetCycCurr > presetCycleMax) presetCycCurr = presetCycleMin;
if (presetCycCurr > 25) presetCycCurr = 1;
colorUpdated(8);
presetCycledTime = millis();
}
}

View File

@@ -49,7 +49,10 @@ TimeChangeRule NZDT = {Second, Sun, Sep, 2, 780 }; //Daylight time = UTC + 13
TimeChangeRule NZST = {First, Sun, Apr, 3, 720 }; //Standard time = UTC + 12 hours
Timezone tzNZ(NZDT, NZST);
Timezone* timezones[] = { &tzUTC, &tzUK, &tzEUCentral, &tzEUEastern, &tzUSEastern, &tzUSCentral, &tzUSMountain, &tzUSArizona, &tzUSPacific, &tzChina, &tzJapan, &tzAUEastern, &tzNZ};
TimeChangeRule NKST = {Last, Sun, Mar, 1, 510}; //Pyongyang Time = UTC + 8.5 hours
Timezone tzNK(NKST, NKST);
Timezone* timezones[] = {&tzUTC, &tzUK, &tzEUCentral, &tzEUEastern, &tzUSEastern, &tzUSCentral, &tzUSMountain, &tzUSArizona, &tzUSPacific, &tzChina, &tzJapan, &tzAUEastern, &tzNZ, &tzNK};
void handleNetworkTime()
{
@@ -69,24 +72,23 @@ void handleNetworkTime()
void sendNTPPacket()
{
const char* ntpsrv = ntpServerName.c_str();
WiFi.hostByName(ntpsrv, ntpServerIP);
WiFi.hostByName(ntpServerName, ntpServerIP);
DEBUG_PRINTLN("send NTP packet");
memset(ntpPacketBuffer, 0, NTP_PACKET_SIZE);
memset(obuf, 0, NTP_PACKET_SIZE);
ntpPacketBuffer[0] = 0b11100011; // LI, Version, Mode
ntpPacketBuffer[1] = 0; // Stratum, or type of clock
ntpPacketBuffer[2] = 6; // Polling Interval
ntpPacketBuffer[3] = 0xEC; // Peer Clock Precision
obuf[0] = 0b11100011; // LI, Version, Mode
obuf[1] = 0; // Stratum, or type of clock
obuf[2] = 6; // Polling Interval
obuf[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
ntpPacketBuffer[12] = 49;
ntpPacketBuffer[13] = 0x4E;
ntpPacketBuffer[14] = 49;
ntpPacketBuffer[15] = 52;
obuf[12] = 49;
obuf[13] = 0x4E;
obuf[14] = 49;
obuf[15] = 52;
ntpUdp.beginPacket(ntpServerIP, 123); //NTP requests are to port 123
ntpUdp.write(ntpPacketBuffer, NTP_PACKET_SIZE);
ntpUdp.write((byte*)obuf, NTP_PACKET_SIZE);
ntpUdp.endPacket();
}
@@ -94,19 +96,19 @@ bool checkNTPResponse()
{
int cb = ntpUdp.parsePacket();
if (cb) {
DEBUG_PRINT("packet received, length=");
DEBUG_PRINT("packet received, l=");
DEBUG_PRINTLN(cb);
ntpUdp.read(ntpPacketBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
ntpUdp.read(obuf, NTP_PACKET_SIZE); // read the packet into the buffer
unsigned long highWord = word(ntpPacketBuffer[40], ntpPacketBuffer[41]);
unsigned long lowWord = word(ntpPacketBuffer[42], ntpPacketBuffer[43]);
unsigned long highWord = word(obuf[40], obuf[41]);
unsigned long lowWord = word(obuf[42], obuf[43]);
if (highWord == 0 && lowWord == 0) return false;
unsigned long secsSince1900 = highWord << 16 | lowWord;
DEBUG_PRINT("Unix time = ");
unsigned long epoch = secsSince1900 - 2208988800UL; //subtract 70 years
unsigned long epoch = secsSince1900 - 2208988799UL; //subtract 70 years -1sec (on avg. more precision)
setTime(epoch);
DEBUG_PRINTLN(epoch);
if (countdownTime - now() > 0) countdownOverTriggered = false;

View File

@@ -27,14 +27,13 @@ void handleAlexa()
int packetSize = UDP.parsePacket();
if(packetSize>0) {
IPAddress remote = UDP.remoteIP();
int len = UDP.read(packetBuffer, 255);
int len = UDP.read(obuf, 254);
if (len > 0) {
packetBuffer[len] = 0;
obuf[len] = 0;
}
String request = packetBuffer;
if(request.indexOf("M-SEARCH") >= 0) {
if(request.indexOf("upnp:rootdevice") > 0 || request.indexOf("device:basic:1") > 0) {
if(strstr(obuf,"M-SEARCH") > 0) {
if(strstr(obuf,"upnp:rootdevice") > 0 || strstr(obuf,"device:basic:1") > 0) {
DEBUG_PRINTLN("Responding search req...");
respondToSearch();
}
@@ -54,12 +53,7 @@ void alexaOn()
applyMacro(macroAlexaOn);
}
String body = "[{\"success\":{\"/lights/1/state/on\":true}}]";
server.send(200, "text/xml", body.c_str());
DEBUG_PRINT("Sending :");
DEBUG_PRINTLN(body);
server.send(200, "application/json", "[{\"success\":{\"/lights/1/state/on\":true}}]");
}
void alexaOff()
@@ -72,19 +66,17 @@ void alexaOff()
applyMacro(macroAlexaOff);
}
String body = "[{\"success\":{\"/lights/1/state/on\":false}}]";
server.send(200, "application/json", body.c_str());
DEBUG_PRINT("Sending:");
DEBUG_PRINTLN(body);
server.send(200, "application/json", "[{\"success\":{\"/lights/1/state/on\":false}}]");
}
void alexaDim(byte briL)
{
String body = "[{\"success\":{\"/lights/1/state/bri\":"+ String(briL) +"}}]";
olen = 0;
oappend("[{\"success\":{\"/lights/1/state/bri\":");
oappendi(briL);
oappend("}}]");
server.send(200, "application/json", body.c_str());
server.send(200, "application/json", obuf);
String ct = (alexaNotify)?"win&IN&A=":"win&NN&IN&A=";
if (briL < 255)
@@ -114,22 +106,29 @@ void respondToSearch() {
char s[16];
sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]);
String response =
olen = 0;
oappend(
"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://");
oappend(s);
oappend(":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: ");
oappend((char*)escapedMac.c_str());
oappend("\r\n"
"ST: urn:schemas-upnp-org:device:basic:1\r\n" // _deviceType
"USN: uuid:2f402f80-da50-11e1-9b23-"+ escapedMac +"::upnp:rootdevice\r\n" // _uuid::_deviceType
"\r\n";
"USN: uuid:2f402f80-da50-11e1-9b23-");
oappend((char*)escapedMac.c_str());
oappend("::upnp:rootdevice\r\n" // _uuid::_deviceType
"\r\n");
UDP.beginPacket(UDP.remoteIP(), UDP.remotePort());
#ifdef ARDUINO_ARCH_ESP32
UDP.write((byte*)response.c_str(), response.length());
UDP.write((byte*)obuf, olen);
#else
UDP.write(response.c_str());
UDP.write(obuf);
#endif
UDP.endPacket();
@@ -144,22 +143,31 @@ void alexaInitPages() {
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\" ?>"
olen = 0;
oappend("<?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://");
oappend(s);
oappend(":80/</URLBase>"
"<device>"
"<deviceType>urn:schemas-upnp-org:device:Basic:1</deviceType>"
"<friendlyName>Philips hue ("+ String(s) +")</friendlyName>"
"<friendlyName>Philips hue (");
oappend(s);
oappend(")</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>");
oappend((char*)escapedMac.c_str());
oappend("</serialNumber>"
"<UDN>uuid:2f402f80-da50-11e1-9b23-");
oappend((char*)escapedMac.c_str());
oappend("</UDN>"
"<presentationURL>index.html</presentationURL>"
"<iconList>"
" <icon>"
@@ -178,12 +186,11 @@ void alexaInitPages() {
" </icon>"
"</iconList>"
"</device>"
"</root>";
"</root>");
server.send(200, "text/xml", setup_xml.c_str());
server.send(200, "text/xml", obuf);
DEBUG_PRINT("Sending :");
DEBUG_PRINTLN(setup_xml);
DEBUG_PRINTLN("Sending setup_xml");
});
// openHAB support
@@ -202,9 +209,9 @@ void alexaInitPages() {
server.on("/status.html", HTTP_GET, [](){
DEBUG_PRINTLN("Got status request");
String statrespone = "0";
char statrespone[] = "0";
if (bri > 0) {
statrespone = "1";
statrespone[0] = '1';
}
server.send(200, "text/plain", statrespone);
@@ -246,14 +253,14 @@ bool handleAlexaApiCall(String req, String body) //basic implementation of Phili
if (req.indexOf("lights/1") > 0) //client wants light info
{
DEBUG_PRINTLN("l1");
server.send(200, "application/json", "{\"manufacturername\":\"OpenSource\",\"modelid\":\"LST001\",\"name\":\""+ alexaInvocationName +"\",\"state\":{\"on\":"+ boolString(bri) +",\"hue\":0,\"bri\":"+ briForHue(bri) +",\"sat\":0,\"xy\":[0.00000,0.00000],\"ct\":500,\"alert\":\"none\",\"effect\":\"none\",\"colormode\":\"hs\",\"reachable\":true},\"swversion\":\"0.1\",\"type\":\"Extended color light\",\"uniqueid\":\"2\"}");
server.send(200, "application/json", "{\"manufacturername\":\"OpenSource\",\"modelid\":\"LST001\",\"name\":\""+ String(alexaInvocationName) +"\",\"state\":{\"on\":"+ boolString(bri) +",\"hue\":0,\"bri\":"+ briForHue(bri) +",\"sat\":0,\"xy\":[0.00000,0.00000],\"ct\":500,\"alert\":\"none\",\"effect\":\"none\",\"colormode\":\"hs\",\"reachable\":true},\"swversion\":\"0.1\",\"type\":\"Extended color light\",\"uniqueid\":\"2\"}");
return true;
}
if (req.indexOf("lights") > 0) //client wants all lights
{
DEBUG_PRINTLN("lAll");
server.send(200, "application/json", "{\"1\":{\"type\":\"Extended color light\",\"manufacturername\":\"OpenSource\",\"swversion\":\"0.1\",\"name\":\""+ alexaInvocationName +"\",\"uniqueid\":\""+ WiFi.macAddress() +"-2\",\"modelid\":\"LST001\",\"state\":{\"on\":"+ boolString(bri) +",\"bri\":"+ briForHue(bri) +",\"xy\":[0.00000,0.00000],\"colormode\":\"hs\",\"effect\":\"none\",\"ct\":500,\"hue\":0,\"sat\":0,\"alert\":\"none\",\"reachable\":true}}}");
server.send(200, "application/json", "{\"1\":{\"type\":\"Extended color light\",\"manufacturername\":\"OpenSource\",\"swversion\":\"0.1\",\"name\":\""+ String(alexaInvocationName) +"\",\"uniqueid\":\""+ WiFi.macAddress() +"-2\",\"modelid\":\"LST001\",\"state\":{\"on\":"+ boolString(bri) +",\"bri\":"+ briForHue(bri) +",\"xy\":[0.00000,0.00000],\"colormode\":\"hs\",\"effect\":\"none\",\"ct\":500,\"hue\":0,\"sat\":0,\"alert\":\"none\",\"reachable\":true}}}");
return true;
}

View File

@@ -1,13 +1,13 @@
/*
* Support for the Cronixie clock
*/
byte getSameCodeLength(char code, int index, char const digits[])
byte getSameCodeLength(char code, int index, char const cronixieDisplay[])
{
byte counter = 0;
for (int i = index+1; i < 6; i++)
{
if (digits[i] == code)
if (cronixieDisplay[i] == code)
{
counter++;
} else {
@@ -19,7 +19,6 @@ byte getSameCodeLength(char code, int index, char const digits[])
void setCronixie()
{
char digits[6]; for (int a=0;a<6;a++) digits[a]=cronixieDisplay.charAt(a);
/*
* digit purpose index
* 0-9 | 0-9 (incl. random)
@@ -84,14 +83,14 @@ void setCronixie()
//D Day of Week | DD Day Of Month | DDD Day Of Year
DEBUG_PRINT("cset ");
DEBUG_PRINTLN(digits);
DEBUG_PRINTLN(cronixieDisplay);
overlayRefreshMs = 1997; //Only refresh every 2secs if no seconds are displayed
for (int i = 0; i < 6; i++)
{
dP[i] = 10;
switch (digits[i])
switch (cronixieDisplay[i])
{
case '_': dP[i] = 10; break;
case '-': dP[i] = 11; break;
@@ -99,24 +98,24 @@ void setCronixie()
case 'R': dP[i] = random(0,10); break; //random btw. 0-9
case 't': break; //Test upw.
case 'T': break; //Test dnw.
case 'b': dP[i] = 14 + getSameCodeLength('b',i,digits); i = i+dP[i]-14; break;
case 'B': dP[i] = 14 + getSameCodeLength('B',i,digits); i = i+dP[i]-14; break;
case 'h': dP[i] = 70 + getSameCodeLength('h',i,digits); i = i+dP[i]-70; break;
case 'H': dP[i] = 20 + getSameCodeLength('H',i,digits); i = i+dP[i]-20; break;
case 'b': dP[i] = 14 + getSameCodeLength('b',i,cronixieDisplay); i = i+dP[i]-14; break;
case 'B': dP[i] = 14 + getSameCodeLength('B',i,cronixieDisplay); i = i+dP[i]-14; break;
case 'h': dP[i] = 70 + getSameCodeLength('h',i,cronixieDisplay); i = i+dP[i]-70; break;
case 'H': dP[i] = 20 + getSameCodeLength('H',i,cronixieDisplay); i = i+dP[i]-20; break;
case 'A': dP[i] = 108; i++; break;
case 'a': dP[i] = 58; i++; break;
case 'm': dP[i] = 74 + getSameCodeLength('m',i,digits); i = i+dP[i]-74; break;
case 'M': dP[i] = 24 + getSameCodeLength('M',i,digits); i = i+dP[i]-24; break;
case 's': dP[i] = 80 + getSameCodeLength('s',i,digits); i = i+dP[i]-80; overlayRefreshMs = 497; break; //refresh more often bc. of secs
case 'S': dP[i] = 30 + getSameCodeLength('S',i,digits); i = i+dP[i]-30; overlayRefreshMs = 497; break;
case 'Y': dP[i] = 36 + getSameCodeLength('Y',i,digits); i = i+dP[i]-36; break;
case 'y': dP[i] = 86 + getSameCodeLength('y',i,digits); i = i+dP[i]-86; break;
case 'I': dP[i] = 39 + getSameCodeLength('I',i,digits); i = i+dP[i]-39; break; //Month. Don't ask me why month and minute both start with M.
case 'i': dP[i] = 89 + getSameCodeLength('i',i,digits); i = i+dP[i]-89; break;
case 'm': dP[i] = 74 + getSameCodeLength('m',i,cronixieDisplay); i = i+dP[i]-74; break;
case 'M': dP[i] = 24 + getSameCodeLength('M',i,cronixieDisplay); i = i+dP[i]-24; break;
case 's': dP[i] = 80 + getSameCodeLength('s',i,cronixieDisplay); i = i+dP[i]-80; overlayRefreshMs = 497; break; //refresh more often bc. of secs
case 'S': dP[i] = 30 + getSameCodeLength('S',i,cronixieDisplay); i = i+dP[i]-30; overlayRefreshMs = 497; break;
case 'Y': dP[i] = 36 + getSameCodeLength('Y',i,cronixieDisplay); i = i+dP[i]-36; break;
case 'y': dP[i] = 86 + getSameCodeLength('y',i,cronixieDisplay); i = i+dP[i]-86; break;
case 'I': dP[i] = 39 + getSameCodeLength('I',i,cronixieDisplay); i = i+dP[i]-39; break; //Month. Don't ask me why month and minute both start with M.
case 'i': dP[i] = 89 + getSameCodeLength('i',i,cronixieDisplay); i = i+dP[i]-89; break;
case 'W': break;
case 'w': break;
case 'D': dP[i] = 43 + getSameCodeLength('D',i,digits); i = i+dP[i]-43; break;
case 'd': dP[i] = 93 + getSameCodeLength('d',i,digits); i = i+dP[i]-93; break;
case 'D': dP[i] = 43 + getSameCodeLength('D',i,cronixieDisplay); i = i+dP[i]-43; break;
case 'd': dP[i] = 93 + getSameCodeLength('d',i,cronixieDisplay); i = i+dP[i]-93; break;
case '0': dP[i] = 0; break;
case '1': dP[i] = 1; break;
case '2': dP[i] = 2; break;

View File

@@ -115,8 +115,6 @@ void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.develo
xy[1] = Y / (X + Y + Z);
}
/*//For some reason min and max are not declared here
float minf (float v, float w)
{
if (w > v) return v;
@@ -129,11 +127,12 @@ float maxf (float v, float w)
return v;
}
void colorRGBtoRGBW(byte* rgb, byte* wht) //rgb to rgbw, untested and currently unused
void colorRGBtoRGBW(byte* rgb, byte* wht) //rgb to rgbw (http://codewelt.com/rgbw)
{
*wht = (float)minf(rgb[0],minf(rgb[1],rgb[2]))*0.95;
rgb[0]-=wht;
rgb[1]-=wht;
rgb[2]-=wht;
}*/
float low = minf(rgb[0],minf(rgb[1],rgb[2]));
float high = maxf(rgb[0],maxf(rgb[1],rgb[2]));
if (high < 0.1f) return;
float sat = 255.0f * ((high - low) / high);
*wht = (byte)((255.0f - sat) / 255.0f * (rgb[0] + rgb[1] + rgb[2]) / 3);
}

View File

@@ -17,18 +17,18 @@ bool setupHue()
{
if (WiFi.status() == WL_CONNECTED) //setup needed
{
if (hueApiKey.length()>20) //api key is probably ok
if (strlen(hueApiKey)>20) //api key is probably ok
{
if (sendHuePoll(false))
{
huePollingEnabled = true;
return true;
}
if (hueError.charAt(0) == 'R' || hueError.charAt(0) == 'I') return false; //can't connect
if (hueError[0] == 'R' || hueError[0] == 'I') return false; //can't connect
delay(20);
}
sendHuePoll(true); //new API key
if (hueError.charAt(0) != 'C') return false; //still some error
if (hueError[0] != 'C') return false; //still some error
delay(20);
if (sendHuePoll(false))
{
@@ -60,7 +60,7 @@ bool sendHuePoll(bool sAuth)
if (httpCode>0){
st = handleHueResponse(hueClient.getString(),sAuth);
} else {
hueError = "Request timed out";
strcpy(hueError,"Request timed out");
st = false;
}
if (!st){ //error
@@ -81,10 +81,13 @@ bool handleHueResponse(String hueResp, bool isAuth)
int hueErrorCode = getJsonValue(&hueResp,"type").toInt();
switch (hueErrorCode)
{
case 1: hueError = "Unauthorized"; break;
case 3: hueError = "Invalid light ID"; break;
case 101: hueError = "Link button not pressed"; break;
default: hueError = "Bridge Error " + String(hueErrorCode);
case 1: strcpy(hueError,"Unauthorized"); break;
case 3: strcpy(hueError,"Invalid light ID"); break;
case 101: strcpy(hueError,"Link button not pressed"); break;
default:
char coerr[18];
sprintf(coerr,"Bridge Error %i",hueErrorCode);
strcpy(hueError,coerr);
}
return false;
}
@@ -94,10 +97,10 @@ bool handleHueResponse(String hueResp, bool isAuth)
String tempApi = getJsonValue(&hueResp,"username");
if (tempApi.length()>0)
{
hueApiKey = tempApi;
strcpy(hueApiKey,tempApi.c_str());
return true;
}
hueError = "Invalid response";
strcpy(hueError,"Invalid response");
return false;
}
@@ -157,11 +160,10 @@ bool handleHueResponse(String hueResp, bool isAuth)
}
hueFailCount = 0;
huePollIntervalMsTemp = huePollIntervalMs;
hueError = "Connected";
strcpy(hueError,"Connected");
//applying vals
if (hueBri != hueBriLast)
{
bri = hueBri;
if (hueApplyOnOff)
{
if (hueBri==0) {bri = 0;}

85
wled00/wled16_blynk.ino Normal file
View File

@@ -0,0 +1,85 @@
/*
* Remote light control with the free Blynk app
*/
uint16_t blHue = 0;
byte blSat = 255;
void initBlynk(const char* auth)
{
if (WiFi.status() != WL_CONNECTED) return;
blynkEnabled = (auth[0] != 0);
if (blynkEnabled) Blynk.config(auth);
}
void handleBlynk()
{
if (WiFi.status() == WL_CONNECTED && blynkEnabled)
Blynk.run();
}
void updateBlynk()
{
Blynk.virtualWrite(V0,bri);
//we need a RGB -> HSB convert here
Blynk.virtualWrite(V3,bri);
Blynk.virtualWrite(V4,effectCurrent);
Blynk.virtualWrite(V5,effectSpeed);
Blynk.virtualWrite(V6,effectIntensity);
Blynk.virtualWrite(V7,nightlightActive);
Blynk.virtualWrite(V8,notifyDirect);
}
BLYNK_WRITE(V0)
{
bri = param.asInt();//bri
colorUpdated(9);
}
BLYNK_WRITE(V1)
{
blHue = param.asInt();//hue
colorHStoRGB(blHue*10,blSat,(false)? colSec:col);
colorUpdated(9);
}
BLYNK_WRITE(V2)
{
blSat = param.asInt();//sat
colorHStoRGB(blHue*10,blSat,(false)? colSec:col);
colorUpdated(9);
}
BLYNK_WRITE(V3)
{
handleSet((param.asInt()>0)?"win&T=1&IN":"win&T=0&IN");//power
}
BLYNK_WRITE(V4)
{
effectCurrent = param.asInt()-1;//fx
colorUpdated(9);
}
BLYNK_WRITE(V5)
{
effectSpeed = param.asInt();//sx
colorUpdated(6);
}
BLYNK_WRITE(V6)
{
effectIntensity = param.asInt();//ix
colorUpdated(6);
}
BLYNK_WRITE(V7)
{
handleSet((param.asInt()>0)?"win&ND&IN":"win&NL=0&IN");//nl
}
BLYNK_WRITE(V8)
{
notifyDirect = (param.asInt()>0); //send notifications
}