Merge branch '4ld-font' into color-order-mapping
This commit is contained in:
commit
6f7f67df5a
@ -45,6 +45,8 @@ class MultiRelay : public Usermod {
|
||||
// status of initialisation
|
||||
bool initDone = false;
|
||||
|
||||
bool HAautodiscovery = false;
|
||||
|
||||
uint16_t periodicBroadcastSec = 60;
|
||||
unsigned long lastBroadcast = 0;
|
||||
|
||||
@ -57,13 +59,14 @@ class MultiRelay : public Usermod {
|
||||
static const char _external[];
|
||||
static const char _button[];
|
||||
static const char _broadcast[];
|
||||
static const char _HAautodiscovery[];
|
||||
|
||||
void publishMqtt(const char* state, int relay) {
|
||||
void publishMqtt(int relay) {
|
||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||
if (WLED_MQTT_CONNECTED){
|
||||
char subuf[64];
|
||||
sprintf_P(subuf, PSTR("%s/relay/%d"), mqttDeviceTopic, relay);
|
||||
mqtt->publish(subuf, 0, false, state);
|
||||
mqtt->publish(subuf, 0, false, _relay[relay].state ? "on" : "off");
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,7 +81,7 @@ class MultiRelay : public Usermod {
|
||||
if (!_relay[i].external) toggleRelay(i);
|
||||
_relay[i].active = false;
|
||||
} else if (periodicBroadcastSec && now - lastBroadcast > (periodicBroadcastSec*1000)) {
|
||||
if (_relay[i].pin>=0) publishMqtt(_relay[i].state ? "on" : "off", i);
|
||||
if (_relay[i].pin>=0) publishMqtt(i);
|
||||
}
|
||||
activeRelays = activeRelays || _relay[i].active;
|
||||
}
|
||||
@ -112,7 +115,7 @@ class MultiRelay : public Usermod {
|
||||
for (int i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
int value = getValue(p->value(), ',', i);
|
||||
if (value==-1) {
|
||||
error = F("There must be as much arugments as relays");
|
||||
error = F("There must be as many arguments as relays");
|
||||
} else {
|
||||
// Switch
|
||||
if (_relay[i].external) switchRelay(i, (bool)value);
|
||||
@ -125,7 +128,7 @@ class MultiRelay : public Usermod {
|
||||
for (int i=0;i<MULTI_RELAY_MAX_RELAYS;i++) {
|
||||
int value = getValue(p->value(), ',', i);
|
||||
if (value==-1) {
|
||||
error = F("There must be as mutch arugments as relays");
|
||||
error = F("There must be as many arguments as relays");
|
||||
} else {
|
||||
// Toggle
|
||||
if (value && _relay[i].external) toggleRelay(i);
|
||||
@ -206,7 +209,7 @@ class MultiRelay : public Usermod {
|
||||
_relay[relay].state = mode;
|
||||
pinMode(_relay[relay].pin, OUTPUT);
|
||||
digitalWrite(_relay[relay].pin, mode ? !_relay[relay].mode : _relay[relay].mode);
|
||||
publishMqtt(mode ? "on" : "off", relay);
|
||||
publishMqtt(relay);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -259,6 +262,50 @@ class MultiRelay : public Usermod {
|
||||
strcpy(subuf, mqttDeviceTopic);
|
||||
strcat_P(subuf, PSTR("/relay/#"));
|
||||
mqtt->subscribe(subuf, 0);
|
||||
if (HAautodiscovery) publishHomeAssistantAutodiscovery();
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].pin<0) continue;
|
||||
publishMqtt(i); //publish current state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void publishHomeAssistantAutodiscovery() {
|
||||
for (uint8_t i = 0; i < MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
char uid[16], json_str[1024], buf[128];
|
||||
size_t payload_size;
|
||||
sprintf_P(uid, PSTR("%s_sw%d"), escapedMac.c_str(), i);
|
||||
|
||||
if (_relay[i].pin >= 0 && _relay[i].external) {
|
||||
StaticJsonDocument<1024> json;
|
||||
sprintf_P(buf, PSTR("%s Switch %d"), serverDescription, i); //max length: 33 + 8 + 3 = 44
|
||||
json[F("name")] = buf;
|
||||
|
||||
sprintf_P(buf, PSTR("%s/relay/%d"), mqttDeviceTopic, i); //max length: 33 + 7 + 3 = 43
|
||||
json["~"] = buf;
|
||||
strcat_P(buf, PSTR("/command"));
|
||||
mqtt->subscribe(buf, 0);
|
||||
|
||||
json[F("stat_t")] = "~";
|
||||
json[F("cmd_t")] = F("~/command");
|
||||
json[F("pl_off")] = F("off");
|
||||
json[F("pl_on")] = F("on");
|
||||
json[F("uniq_id")] = uid;
|
||||
|
||||
strcpy(buf, mqttDeviceTopic); //max length: 33 + 7 = 40
|
||||
strcat_P(buf, PSTR("/status"));
|
||||
json[F("avty_t")] = buf;
|
||||
json[F("pl_avail")] = F("online");
|
||||
json[F("pl_not_avail")] = F("offline");
|
||||
//TODO: dev
|
||||
payload_size = serializeJson(json, json_str);
|
||||
} else {
|
||||
//Unpublish disabled or internal relays
|
||||
json_str[0] = 0;
|
||||
payload_size = 0;
|
||||
}
|
||||
sprintf_P(buf, PSTR("homeassistant/switch/%s/config"), uid);
|
||||
mqtt->publish(buf, 0, true, json_str, payload_size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -320,13 +367,18 @@ class MultiRelay : public Usermod {
|
||||
*/
|
||||
bool handleButton(uint8_t b) {
|
||||
yield();
|
||||
if (buttonType[b] == BTN_TYPE_NONE || buttonType[b] == BTN_TYPE_RESERVED || buttonType[b] == BTN_TYPE_PIR_SENSOR || buttonType[b] == BTN_TYPE_ANALOG || buttonType[b] == BTN_TYPE_ANALOG_INVERTED) {
|
||||
if (!enabled
|
||||
|| buttonType[b] == BTN_TYPE_NONE
|
||||
|| buttonType[b] == BTN_TYPE_RESERVED
|
||||
|| buttonType[b] == BTN_TYPE_PIR_SENSOR
|
||||
|| buttonType[b] == BTN_TYPE_ANALOG
|
||||
|| buttonType[b] == BTN_TYPE_ANALOG_INVERTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].button == b) {
|
||||
if (_relay[i].button == b && _relay[i].external) {
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
@ -362,6 +414,8 @@ class MultiRelay : public Usermod {
|
||||
buttonPressedBefore[b] = true;
|
||||
|
||||
if (now - buttonPressedTime[b] > 600) { //long press
|
||||
//longPressAction(b); //not exposed
|
||||
//handled = false; //use if you want to pass to default behaviour
|
||||
buttonLongPressed[b] = true;
|
||||
}
|
||||
|
||||
@ -378,7 +432,8 @@ class MultiRelay : public Usermod {
|
||||
if (!buttonLongPressed[b]) { //short press
|
||||
// if this is second release within 350ms it is a double press (buttonWaitTime!=0)
|
||||
if (doublePress) {
|
||||
//doublePressAction(b);
|
||||
//doublePressAction(b); //not exposed
|
||||
//handled = false; //use if you want to pass to default behaviour
|
||||
} else {
|
||||
buttonWaitTime[b] = now;
|
||||
}
|
||||
@ -386,9 +441,10 @@ class MultiRelay : public Usermod {
|
||||
buttonPressedBefore[b] = false;
|
||||
buttonLongPressed[b] = false;
|
||||
}
|
||||
// if 450ms elapsed since last press/release it is a short press
|
||||
// if 350ms elapsed since last press/release it is a short press
|
||||
if (buttonWaitTime[b] && now - buttonWaitTime[b] > 350 && !buttonPressedBefore[b]) {
|
||||
buttonWaitTime[b] = 0;
|
||||
//shortPressAction(b); //not exposed
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
if (_relay[i].pin>=0 && _relay[i].button == b) {
|
||||
toggleRelay(i);
|
||||
@ -494,6 +550,7 @@ class MultiRelay : public Usermod {
|
||||
relay[FPSTR(_external)] = _relay[i].external;
|
||||
relay[FPSTR(_button)] = _relay[i].button;
|
||||
}
|
||||
top[FPSTR(_HAautodiscovery)] = HAautodiscovery;
|
||||
DEBUG_PRINTLN(F("MultiRelay config saved."));
|
||||
}
|
||||
|
||||
@ -516,6 +573,7 @@ class MultiRelay : public Usermod {
|
||||
enabled = top[FPSTR(_enabled)] | enabled;
|
||||
periodicBroadcastSec = top[FPSTR(_broadcast)] | periodicBroadcastSec;
|
||||
periodicBroadcastSec = min(900,max(0,(int)periodicBroadcastSec));
|
||||
HAautodiscovery = top[FPSTR(_HAautodiscovery)] | HAautodiscovery;
|
||||
|
||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||
@ -583,3 +641,4 @@ const char MultiRelay::_activeHigh[] PROGMEM = "active-high";
|
||||
const char MultiRelay::_external[] PROGMEM = "external";
|
||||
const char MultiRelay::_button[] PROGMEM = "button";
|
||||
const char MultiRelay::_broadcast[] PROGMEM = "broadcast-sec";
|
||||
const char MultiRelay::_HAautodiscovery[] PROGMEM = "HA-autodiscovery";
|
||||
|
@ -2,9 +2,10 @@
|
||||
|
||||
//WLED custom fonts, curtesy of @Benji (https://github.com/Proto-molecule)
|
||||
|
||||
|
||||
/*
|
||||
Fontname: wled_logo_akemi_4x4
|
||||
Copyright:
|
||||
Copyright: Benji (https://github.com/proto-molecule)
|
||||
Glyphs: 3/3
|
||||
BBX Build Mode: 3
|
||||
* this logo ...WLED/images/wled_logo_akemi.png
|
||||
@ -28,7 +29,7 @@ const uint8_t u8x8_wled_logo_akemi_4x4[388] U8X8_FONT_SECTION("u8x8_wled_logo_ak
|
||||
|
||||
/*
|
||||
Fontname: wled_logo_akemi_5x5
|
||||
Copyright: Created with Fony 1.4.7
|
||||
Copyright: Benji (https://github.com/proto-molecule)
|
||||
Glyphs: 3/3
|
||||
BBX Build Mode: 3
|
||||
* this logo ...WLED/images/wled_logo_akemi.png
|
||||
@ -59,7 +60,7 @@ const uint8_t u8x8_wled_logo_akemi_5x5[604] U8X8_FONT_SECTION("u8x8_wled_logo_ak
|
||||
|
||||
/*
|
||||
Fontname: wled_logo_2x2
|
||||
Copyright: Created with Fony 1.4.7
|
||||
Copyright: Benji (https://github.com/proto-molecule)
|
||||
Glyphs: 4/4
|
||||
BBX Build Mode: 3
|
||||
* this logo https://cdn.discordapp.com/attachments/706623245935444088/927361780613799956/wled_scaled.png
|
||||
@ -105,7 +106,7 @@ const uint8_t u8x8_wled_logo_4x4[517] U8X8_FONT_SECTION("u8x8_wled_logo_4x4") =
|
||||
|
||||
/*
|
||||
Fontname: 4LineDisplay_WLED_icons_1x
|
||||
Copyright:
|
||||
Copyright: Benji (https://github.com/proto-molecule)
|
||||
Glyphs: 13/13
|
||||
BBX Build Mode: 3
|
||||
* 1 = sun
|
||||
@ -133,6 +134,33 @@ const uint8_t u8x8_4LineDisplay_WLED_icons_1x1[172] U8X8_FONT_SECTION("u8x8_4Lin
|
||||
"\311\1\2\0\0~<<\30\30\0";
|
||||
|
||||
|
||||
/*
|
||||
Fontname: 4LineDisplay_WLED_icons_2x1
|
||||
Copyright: Benji (https://github.com/proto-molecule)
|
||||
Glyphs: 11/11
|
||||
BBX Build Mode: 3
|
||||
* 1 = sun
|
||||
* 2 = skip forward
|
||||
* 3 = fire
|
||||
* 4 = custom palette
|
||||
* 5 = puzzle piece
|
||||
* 6 = moon
|
||||
* 7 = brush
|
||||
* 8 = contrast
|
||||
* 9 = power-standby
|
||||
* 10 = star
|
||||
* 11 = heart
|
||||
* 12 = Akemi
|
||||
*/
|
||||
const uint8_t u8x8_4LineDisplay_WLED_icons_2x1[196] U8X8_FONT_SECTION("u8x8_4LineDisplay_WLED_icons_2x1") =
|
||||
"\1\14\2\1\20\20BB\30\30<\275\275<\30\30BB\20\20\377~<<\70\30\20\0\377~<<"
|
||||
"\70\30\20\0\60p\370\374\77>\236\214\300\340\370\360\360\340\0\0\34<v\326\336\375\375\377\277\275=>"
|
||||
"\66\66<\34\374\374\374\374~\77\77~\374\374\374\374 pp \30<~~\377\370\360\360\340\340\340\340"
|
||||
"@@ \0\200\300\340\360\360p`\10\34\34\16\6\6\3\0\0\70|~\376\376\377\377\377\201\201\203\202"
|
||||
"\302Fl\70\70xL\204\200\200\217\217\200\200\204Lx\70\0\0\10\10\30\330x|\77\77|x\330\30"
|
||||
"\10\10\0\0\14\36\37\77\77\177~\374\374~\177\77\77\37\36\14\24\64 \60>\26\367\33\375\36>\60"
|
||||
" \64\24";
|
||||
|
||||
|
||||
/*
|
||||
Fontname: 4LineDisplay_WLED_icons_2x
|
||||
@ -167,9 +195,59 @@ const uint8_t u8x8_4LineDisplay_WLED_icons_2x2[389] U8X8_FONT_SECTION("u8x8_4Lin
|
||||
"\7\3\1\0\200\200\0\0\0\360\370\374<\334\330\360\0\0\200\200\2\2\14\30\24\37\6~\7\177\7\37"
|
||||
"\24\30\16\2";
|
||||
|
||||
/*
|
||||
Fontname: 4LineDisplay_WLED_icons_3x
|
||||
Copyright: Benji (https://github.com/proto-molecule)
|
||||
Glyphs: 11/11
|
||||
BBX Build Mode: 3
|
||||
* 1 = sun
|
||||
* 2 = skip forward
|
||||
* 3 = fire
|
||||
* 4 = custom palette
|
||||
* 5 = puzzle piece
|
||||
* 6 = moon
|
||||
* 7 = brush
|
||||
* 8 = contrast
|
||||
* 9 = power-standby
|
||||
* 10 = star
|
||||
* 11 = heart
|
||||
* 12 = Akemi
|
||||
*/
|
||||
const uint8_t u8x8_4LineDisplay_WLED_icons_3x3[868] U8X8_FONT_SECTION("u8x8_4LineDisplay_WLED_icons_3x3") =
|
||||
"\1\14\3\3\0\0\34\34\34\0\200\300\300\340\347\347\347\340\300\300\200\0\34\34\34\0\0\0\34\34\34\0"
|
||||
"\0>\377\377\377\377\377\377\377\377\377\377\377>\0\0\34\34\34\0\0\0\16\16\16\0\0\1\1\3ss"
|
||||
"s\3\1\1\0\0\34\34\34\0\0\0\370\360\340\300\300\200\0\0\0\0\0\0\370\360\340\300\300\200\0\0"
|
||||
"\0\0\0\0\377\377\377\377\377\377\377\376~<\70\20\377\377\377\377\377\377\377\376~<\70\20\37\17\17\7"
|
||||
"\3\1\1\0\0\0\0\0\37\17\17\7\3\1\1\0\0\0\0\0\0\0\0\0\0\300\361\376\374\370\360\300"
|
||||
"\0\0\0\0\0\0\0\0\0\0\0\0\300\370\374\376\377\377\377\377\377\177\77\17\6\0\200\342\374\370\360\340"
|
||||
"\200\0\0\0\1\17\37\77\177\377\7\3\0\200\360\370\374\376\377\377\377\377\377\377\77\0\0\0\0\200\340\360"
|
||||
"\370\370\374\316\206\206\317\377\377\377\317\206\206\316\374\374\370\360\340\200<\377\377\371\360py\377\377\377\377\377"
|
||||
"\377\377\377\377\377\377\363\341\341\363\377\177\0\1\7\17\34\70x|\377\377\377\377\367\363c\3\3\3\3\1"
|
||||
"\1\1\0\0\300\300\300\300\300\300\300\316\377\377\377\316\300\300\300\300\300\300\0\0\0\0\0\0\377\377\377\377"
|
||||
"\377\377\377\377\377\377\377\377\377\377\377\377\377\377\300\300\340\340\340\300\377\377\377\377\377\377\377\307\3\3\3\307"
|
||||
"\377\377\377\377\377\377\1\1\3\3\3\1\0\300\340\370\374\374\376\377\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\0>\377\377\377\377\377\377\377\377\374\360\340\300\300\200\200\0\0\0\0\0\0\200\200\0\1\7\17"
|
||||
"\37\37\77\177\177\177\177\377\377\377\177\177\177\77\77\37\17\7\3\0\0\0\0\0\0\0\0\0\0\0\0\0"
|
||||
"\200\200\300\340\340\360\370\374|>\17\6\0\0\0\0\0\340\340\360\360\360\342\303\7\17\37\77\37\7\3\1"
|
||||
"\0\0\0\0\0\200\340\360\377\377\377\377\177\77\37\17\0\0\0\0\0\0\0\0\0\0\0\0\0\200\340\360"
|
||||
"\370\374\374\376\376\376\377\377\7\7\7\6\16\16\34\70\360\340\300\0|\377\377\377\377\377\377\377\377\377\377\377"
|
||||
"\0\0\0\0\0\0\0\0\0\377\377\377\0\3\7\17\37\77\177\177\377\377\377\377\340\340\340\340pp\70<"
|
||||
"\37\17\3\0\0\0\200\300\340\340\300\0\0\377\377\377\0\0\300\340\340\300\200\0\0\0\0\0\370\376\377\17"
|
||||
"\3\0\0\0\0\17\17\17\0\0\0\0\0\3\17\377\376\370\0\0\0\7\17\37<xp\340\340\340\340\340"
|
||||
"\340\340\340px<\37\17\3\0\0\0\0\0\0\0\0\0\0\0\0\0\300\370\376\370\200\0\0\0\0\0"
|
||||
"\0\0\0\0\0\2\6\16\36\36>~\376\376\377\377\377\377\377\376\376~>\36\16\6\6\2\0\0\0\0"
|
||||
"\0\300x<\37\17\17\7\3\7\17\17\37<x\300\0\0\0\0\200\300\340\360\360\370\370\370\360\360\340\300"
|
||||
"\200\300\340\360\360\370\370\370\360\360\340\200\17\37\77\177\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
|
||||
"\177\77\37\17\0\0\0\0\0\1\3\7\17\37\77\177\177\77\37\17\7\3\1\0\0\0\0\0\0\0\0\0"
|
||||
"\0\0\0\200\300\340\360\370\370\370p`\300\200\0\0\0\0\0\0&,f\300\0\0\300\377\377\357\357\357"
|
||||
"\363\370\377\377\377\377\300\0\0\306l&\0\0\0\1\7\16\14\6\7\1\177\177\0\177\177\1\7\6\14\16"
|
||||
"\7\1\0";
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Fontname: 4LineDisplay_WLED_icons_4x
|
||||
Copyright:
|
||||
Copyright: Benji (https://github.com/proto-molecule)
|
||||
Glyphs: 11/11
|
||||
BBX Build Mode: 3
|
||||
* 1 = sun
|
||||
@ -240,7 +318,7 @@ const uint8_t u8x8_4LineDisplay_WLED_icons_4x4[1540] U8X8_FONT_SECTION("u8x8_4Li
|
||||
|
||||
/*
|
||||
Fontname: 4LineDisplay_WLED_icons_6x
|
||||
Copyright:
|
||||
Copyright: Benji (https://github.com/proto-molecule)
|
||||
Glyphs: 11/11
|
||||
BBX Build Mode: 3
|
||||
* 1 = sun
|
||||
@ -256,6 +334,7 @@ const uint8_t u8x8_4LineDisplay_WLED_icons_4x4[1540] U8X8_FONT_SECTION("u8x8_4Li
|
||||
* 11 = heart
|
||||
* 12 = Akemi
|
||||
*/
|
||||
// you can replace this (wasteful) font by using 3x3 variant with draw2x2Glyph()
|
||||
const uint8_t u8x8_4LineDisplay_WLED_icons_6x6[3460] U8X8_FONT_SECTION("u8x8_4LineDisplay_WLED_icons_6x6") =
|
||||
"\1\14\6\6\0\0\0\0\0\0\200\300\300\300\300\200\0\0\0\0\0\0\0\0\0\36\77\77\77\77\36\0"
|
||||
"\0\0\0\0\0\0\0\0\200\300\300\300\300\200\0\0\0\0\0\0\0\0\0\0\0\0\7\17\17\17\17\7"
|
||||
@ -371,7 +450,7 @@ const uint8_t u8x8_4LineDisplay_WLED_icons_6x6[3460] U8X8_FONT_SECTION("u8x8_4Li
|
||||
|
||||
/*
|
||||
Fontname: akemi_8x8
|
||||
Copyright: Created with Fony 1.4.7
|
||||
Copyright: Benji (https://github.com/proto-molecule)
|
||||
Glyphs: 1/1
|
||||
BBX Build Mode: 3
|
||||
* 12 = Akemi
|
||||
|
@ -119,6 +119,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
|
||||
// HW interface & configuration
|
||||
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
|
||||
|
||||
#ifndef FLD_SPI_DEFAULT
|
||||
int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA
|
||||
uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000)
|
||||
@ -126,6 +127,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST
|
||||
uint32_t ioFrequency = 1000000; // in Hz (minimum is 500kHz, baseline is 1MHz and maximum should be 20MHz)
|
||||
#endif
|
||||
|
||||
DisplayType type = FLD_TYPE; // display type
|
||||
bool flip = false; // flip display 180°
|
||||
uint8_t contrast = 10; // screen contrast
|
||||
@ -136,6 +138,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
bool clockMode = false; // display clock
|
||||
bool showSeconds = true; // display clock with seconds
|
||||
bool enabled = true;
|
||||
bool contrastFix = false;
|
||||
|
||||
// Next variables hold the previous known values to determine if redraw is
|
||||
// required.
|
||||
@ -175,6 +178,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
static const char _clockMode[];
|
||||
static const char _showSeconds[];
|
||||
static const char _busClkFrequency[];
|
||||
static const char _contrastFix[];
|
||||
|
||||
// If display does not work or looks corrupted check the
|
||||
// constructor reference:
|
||||
@ -182,6 +186,15 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
// or check the gallery:
|
||||
// https://github.com/olikraus/u8g2/wiki/gallery
|
||||
|
||||
// some displays need this to properly apply contrast
|
||||
void setVcomh(bool highContrast) {
|
||||
u8x8_t *u8x8_struct = u8x8->getU8x8();
|
||||
u8x8_cad_StartTransfer(u8x8_struct);
|
||||
u8x8_cad_SendCmd(u8x8_struct, 0x0db); //address of value
|
||||
u8x8_cad_SendArg(u8x8_struct, highContrast ? 0x000 : 0x040); //value 0 for fix, reboot resets default back to 64
|
||||
u8x8_cad_EndTransfer(u8x8_struct);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// gets called once at boot. Do all initialization that doesn't depend on
|
||||
@ -189,9 +202,9 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
void setup() {
|
||||
if (type == NONE || !enabled) return;
|
||||
|
||||
bool isHW;
|
||||
bool isHW, isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64);
|
||||
PinOwner po = PinOwner::UM_FourLineDisplay;
|
||||
if (type == SSD1306_SPI || type == SSD1306_SPI64) {
|
||||
if (isSPI) {
|
||||
isHW = (ioPin[0]==HW_PIN_CLOCKSPI && ioPin[1]==HW_PIN_DATASPI);
|
||||
PinManagerPinType pins[5] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true }, { ioPin[3], true }, { ioPin[4], true }};
|
||||
if (!pinManager.allocateMultiplePins(pins, 5, po)) { type=NONE; return; }
|
||||
@ -203,41 +216,72 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
}
|
||||
|
||||
DEBUG_PRINTLN(F("Allocating display."));
|
||||
/*
|
||||
// At some point it may be good to not new/delete U8X8 object but use this instead
|
||||
// (does not currently work)
|
||||
//-------------------------------------------------------------------------------
|
||||
switch (type) {
|
||||
case SSD1306:
|
||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x32_univision, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino);
|
||||
break;
|
||||
case SH1106:
|
||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_sh1106_128x64_winstar, u8x8_cad_ssd13xx_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino);
|
||||
break;
|
||||
case SSD1306_64:
|
||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino);
|
||||
break;
|
||||
case SSD1305:
|
||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1305_128x32_adafruit, u8x8_cad_ssd13xx_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
||||
break;
|
||||
case SSD1305_64:
|
||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1305_128x64_adafruit, u8x8_cad_ssd13xx_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino);
|
||||
break;
|
||||
case SSD1306_SPI:
|
||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x32_univision, u8x8_cad_001, u8x8_byte_arduino_4wire_sw_spi, u8x8_gpio_and_delay_arduino);
|
||||
break;
|
||||
case SSD1306_SPI64:
|
||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_001, u8x8_byte_arduino_4wire_sw_spi, u8x8_gpio_and_delay_arduino);
|
||||
break;
|
||||
default:
|
||||
type = NONE;
|
||||
return;
|
||||
}
|
||||
if (isSPI) {
|
||||
if (!isHW) u8x8_SetPin_4Wire_SW_SPI(u8x8.getU8x8(), ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]);
|
||||
else u8x8_SetPin_4Wire_HW_SPI(u8x8.getU8x8(), ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset
|
||||
} else {
|
||||
if (!isHW) u8x8_SetPin_SW_I2C(u8x8.getU8x8(), ioPin[0], ioPin[1], U8X8_PIN_NONE); // SCL, SDA, reset
|
||||
else u8x8_SetPin_HW_I2C(u8x8.getU8x8(), U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
|
||||
}
|
||||
*/
|
||||
switch (type) {
|
||||
case SSD1306:
|
||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
|
||||
else u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
|
||||
lineHeight = 1;
|
||||
break;
|
||||
case SH1106:
|
||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
|
||||
else u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
|
||||
lineHeight = 2;
|
||||
break;
|
||||
case SSD1306_64:
|
||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
|
||||
else u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
|
||||
lineHeight = 2;
|
||||
break;
|
||||
case SSD1305:
|
||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
|
||||
else u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
|
||||
lineHeight = 1;
|
||||
break;
|
||||
case SSD1305_64:
|
||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
|
||||
else u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
|
||||
lineHeight = 2;
|
||||
break;
|
||||
case SSD1306_SPI:
|
||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]);
|
||||
else u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset
|
||||
lineHeight = 1;
|
||||
break;
|
||||
case SSD1306_SPI64:
|
||||
if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]);
|
||||
else u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset
|
||||
lineHeight = 2;
|
||||
break;
|
||||
default:
|
||||
u8x8 = nullptr;
|
||||
@ -245,20 +289,22 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
|
||||
if (nullptr == u8x8) {
|
||||
DEBUG_PRINTLN(F("Display init failed."));
|
||||
pinManager.deallocateMultiplePins((const uint8_t*)ioPin, (type == SSD1306_SPI || type == SSD1306_SPI64) ? 5 : 2, po);
|
||||
pinManager.deallocateMultiplePins((const uint8_t*)ioPin, isSPI ? 5 : 2, po);
|
||||
type = NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
initDone = true;
|
||||
lineHeight = u8x8->getRows() > 4 ? 2 : 1;
|
||||
DEBUG_PRINTLN(F("Starting display."));
|
||||
/*if (!(type == SSD1306_SPI || type == SSD1306_SPI64))*/ u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||
u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||
u8x8->begin();
|
||||
setFlipMode(flip);
|
||||
setVcomh(contrastFix);
|
||||
setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||
setPowerSave(0);
|
||||
//drawString(0, 0, "Loading...");
|
||||
overlayLogo(3500);
|
||||
initDone = true;
|
||||
}
|
||||
|
||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||
@ -379,30 +425,29 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
String timer = PSTR("Timer On");
|
||||
center(timer,LINE_BUFFER_SIZE-1);
|
||||
overlay(timer.c_str(), 2500, 6);
|
||||
//lastRedraw = millis();
|
||||
}
|
||||
return;
|
||||
} else if (wificonnected != interfacesInited) { //trigger wifi icon
|
||||
wificonnected = interfacesInited;
|
||||
drawStatusIcons();
|
||||
return;
|
||||
} else if (knownMode != effectCurrent) {
|
||||
knownMode = effectCurrent;
|
||||
} else if (knownMode != effectCurrent || knownPalette != effectPalette) {
|
||||
if (displayTurnedOff) needRedraw = true;
|
||||
else { showCurrentEffectOrPalette(knownMode, JSON_mode_names, 3); return; }
|
||||
} else if (knownPalette != effectPalette) {
|
||||
knownPalette = effectPalette;
|
||||
if (displayTurnedOff) needRedraw = true;
|
||||
else { showCurrentEffectOrPalette(knownPalette, JSON_palette_names, 2); return; }
|
||||
else {
|
||||
if (knownPalette != effectPalette) { showCurrentEffectOrPalette(effectPalette, JSON_palette_names, 2); knownPalette = effectPalette; }
|
||||
if (knownMode != effectCurrent) { showCurrentEffectOrPalette(effectCurrent, JSON_mode_names, 3); knownMode = effectCurrent; }
|
||||
lastRedraw = now;
|
||||
return;
|
||||
}
|
||||
} else if (knownBrightness != bri) {
|
||||
if (displayTurnedOff && nightlightActive) { knownBrightness = bri; }
|
||||
else if (!displayTurnedOff) { updateBrightness(); return; }
|
||||
else if (!displayTurnedOff) { updateBrightness(); lastRedraw = now; return; }
|
||||
} else if (knownEffectSpeed != effectSpeed) {
|
||||
if (displayTurnedOff) needRedraw = true;
|
||||
else { updateSpeed(); return; }
|
||||
else { updateSpeed(); lastRedraw = now; return; }
|
||||
} else if (knownEffectIntensity != effectIntensity) {
|
||||
if (displayTurnedOff) needRedraw = true;
|
||||
else { updateIntensity(); return; }
|
||||
else { updateIntensity(); lastRedraw = now; return; }
|
||||
}
|
||||
|
||||
if (!needRedraw) {
|
||||
@ -425,13 +470,13 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
wakeDisplay();
|
||||
|
||||
// Update last known values.
|
||||
knownBrightness = bri;
|
||||
knownMode = effectCurrent;
|
||||
knownPalette = effectPalette;
|
||||
knownEffectSpeed = effectSpeed;
|
||||
knownBrightness = bri;
|
||||
knownMode = effectCurrent;
|
||||
knownPalette = effectPalette;
|
||||
knownEffectSpeed = effectSpeed;
|
||||
knownEffectIntensity = effectIntensity;
|
||||
knownnightlight = nightlightActive;
|
||||
wificonnected = interfacesInited;
|
||||
knownnightlight = nightlightActive;
|
||||
wificonnected = interfacesInited;
|
||||
|
||||
// Do the actual drawing
|
||||
// First row: Icons
|
||||
@ -492,9 +537,9 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
drawGlyph(14, 2*lineHeight, 4, u8x8_4LineDisplay_WLED_icons_2x2, true); //palette icon
|
||||
drawGlyph(14, 3*lineHeight, 5, u8x8_4LineDisplay_WLED_icons_2x2, true); //effect icon
|
||||
} else {
|
||||
drawGlyph( 2, 0, 1, u8x8_4LineDisplay_WLED_icons_1x1); //brightness icon
|
||||
drawGlyph( 6, 0, 2, u8x8_4LineDisplay_WLED_icons_1x1); //speed icon
|
||||
drawGlyph(10, 0, 3, u8x8_4LineDisplay_WLED_icons_1x1); //intensity icon
|
||||
drawGlyph( 1, 0, 1, u8x8_4LineDisplay_WLED_icons_2x1); //brightness icon
|
||||
drawGlyph( 5, 0, 2, u8x8_4LineDisplay_WLED_icons_2x1); //speed icon
|
||||
drawGlyph( 9, 0, 3, u8x8_4LineDisplay_WLED_icons_2x1); //intensity icon
|
||||
drawGlyph(15, 2, 4, u8x8_4LineDisplay_WLED_icons_1x1); //palette icon
|
||||
drawGlyph(15, 3, 5, u8x8_4LineDisplay_WLED_icons_1x1); //effect icon
|
||||
}
|
||||
@ -506,7 +551,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
drawGlyph(col, row, (wificonnected ? 20 : 0), u8x8_4LineDisplay_WLED_icons_1x1, true); // wifi icon
|
||||
if (lineHeight==2) { col--; } else { row++; }
|
||||
drawGlyph(col, row, (bri > 0 ? 9 : 0), u8x8_4LineDisplay_WLED_icons_1x1, true); // power icon
|
||||
if (lineHeight==2) { col--; } else { row++; col = row = 0; }
|
||||
if (lineHeight==2) { col--; } else { col = row = 0; }
|
||||
drawGlyph(col, row, (nightlightActive ? 6 : 0), u8x8_4LineDisplay_WLED_icons_1x1, true); // moon icon for nighlight mode
|
||||
}
|
||||
|
||||
@ -529,18 +574,21 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
// on the appropriate line (row).
|
||||
void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row) {
|
||||
char lineBuffer[MAX_JSON_CHARS];
|
||||
knownMode = effectCurrent;
|
||||
knownPalette = effectPalette;
|
||||
if (overlayUntil == 0) {
|
||||
// Find the mode name in JSON
|
||||
uint8_t printedChars = extractModeName(inputEffPal, qstring, lineBuffer, MAX_JSON_CHARS-1);
|
||||
if (lineBuffer[0]=='*' && lineBuffer[1]==' ') {
|
||||
// remove "* " from dynamic palettes
|
||||
for (byte i=2; i<=printedChars; i++) lineBuffer[i-2] = lineBuffer[i]; //include '\0'
|
||||
printedChars -= 2;
|
||||
}
|
||||
if (lineHeight == 2) { // use this code for 8 line display
|
||||
char smallBuffer1[MAX_MODE_LINE_SPACE];
|
||||
char smallBuffer2[MAX_MODE_LINE_SPACE];
|
||||
uint8_t smallChars1 = 0;
|
||||
uint8_t smallChars2 = 0;
|
||||
if (printedChars < MAX_MODE_LINE_SPACE) { // use big font if the text fits
|
||||
for (;printedChars < (MAX_MODE_LINE_SPACE-1); printedChars++) lineBuffer[printedChars]=' ';
|
||||
while (printedChars < (MAX_MODE_LINE_SPACE-1)) lineBuffer[printedChars++]=' ';
|
||||
lineBuffer[printedChars] = 0;
|
||||
drawString(1, row*lineHeight, lineBuffer);
|
||||
} else { // for long names divide the text into 2 lines and print them small
|
||||
@ -561,23 +609,20 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (; smallChars1 < (MAX_MODE_LINE_SPACE-1); smallChars1++) smallBuffer1[smallChars1]=' ';
|
||||
while (smallChars1 < (MAX_MODE_LINE_SPACE-1)) smallBuffer1[smallChars1++]=' ';
|
||||
smallBuffer1[smallChars1] = 0;
|
||||
drawString(1, row*lineHeight, smallBuffer1, true);
|
||||
for (; smallChars2 < (MAX_MODE_LINE_SPACE-1); smallChars2++) smallBuffer2[smallChars2]=' ';
|
||||
while (smallChars2 < (MAX_MODE_LINE_SPACE-1)) smallBuffer2[smallChars2++]=' ';
|
||||
smallBuffer2[smallChars2] = 0;
|
||||
drawString(1, row*lineHeight+1, smallBuffer2, true);
|
||||
}
|
||||
} else { // use this code for 4 ling displays
|
||||
char smallBuffer3[MAX_MODE_LINE_SPACE+1];
|
||||
char smallBuffer3[MAX_MODE_LINE_SPACE+1]; // uses 1x1 icon for mode/palette
|
||||
uint8_t smallChars3 = 0;
|
||||
if (printedChars > MAX_MODE_LINE_SPACE) printedChars = MAX_MODE_LINE_SPACE;
|
||||
for (uint8_t i = 0; i < printedChars; i++) smallBuffer3[smallChars3++] = lineBuffer[i];
|
||||
for (; smallChars3 < (MAX_MODE_LINE_SPACE); smallChars3++) smallBuffer3[smallChars3]=' ';
|
||||
for (uint8_t i = 0; i < MAX_MODE_LINE_SPACE; i++) smallBuffer3[smallChars3++] = (i >= printedChars) ? ' ' : lineBuffer[i];
|
||||
smallBuffer3[smallChars3] = 0;
|
||||
drawString(1, row*lineHeight, smallBuffer3, true);
|
||||
}
|
||||
lastRedraw = millis();
|
||||
}
|
||||
}
|
||||
|
||||
@ -609,8 +654,8 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
if (!wakeDisplay()) clear();
|
||||
// Print the overlay
|
||||
if (glyphType>0 && glyphType<255) {
|
||||
if (lineHeight == 2) drawGlyph(5, 0, glyphType, u8x8_4LineDisplay_WLED_icons_6x6, true);
|
||||
else drawGlyph(7, lineHeight, glyphType, u8x8_4LineDisplay_WLED_icons_2x2, true);
|
||||
if (lineHeight == 2) drawGlyph(5, 0, glyphType, u8x8_4LineDisplay_WLED_icons_6x6, true); // use 3x3 font with draw2x2Glyph() if flash runs short and comment out 6x6 font
|
||||
else drawGlyph(6, 0, glyphType, u8x8_4LineDisplay_WLED_icons_3x3, true);
|
||||
}
|
||||
if (line1) {
|
||||
String buf = line1;
|
||||
@ -646,7 +691,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
break;
|
||||
case 2:
|
||||
//Akemi
|
||||
//draw2x2Glyph( 4, 0, 12, u8x8_4LineDisplay_WLED_icons_4x4);
|
||||
//draw2x2Glyph( 5, 0, 12, u8x8_4LineDisplay_WLED_icons_3x3); // use this if flash runs short and comment out 6x6 font
|
||||
drawGlyph( 5, 0, 12, u8x8_4LineDisplay_WLED_icons_6x6, true);
|
||||
drawString(6, 6, "WLED");
|
||||
break;
|
||||
@ -668,7 +713,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
break;
|
||||
case 2:
|
||||
//Akemi
|
||||
//drawGlyph( 6, 0, 12, u8x8_4LineDisplay_WLED_icons_4x4);
|
||||
//drawGlyph( 6, 0, 12, u8x8_4LineDisplay_WLED_icons_4x4); // a bit nicer, but uses extra 1.5k flash
|
||||
draw2x2Glyph( 6, 0, 12, u8x8_4LineDisplay_WLED_icons_2x2);
|
||||
break;
|
||||
}
|
||||
@ -795,6 +840,80 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* handleButton() can be used to override default button behaviour. Returning true
|
||||
* will prevent button working in a default way.
|
||||
* Replicating button.cpp
|
||||
*/
|
||||
bool handleButton(uint8_t b) {
|
||||
yield();
|
||||
if (!enabled
|
||||
|| b // butto 0 only
|
||||
|| buttonType[b] == BTN_TYPE_SWITCH
|
||||
|| buttonType[b] == BTN_TYPE_NONE
|
||||
|| buttonType[b] == BTN_TYPE_RESERVED
|
||||
|| buttonType[b] == BTN_TYPE_PIR_SENSOR
|
||||
|| buttonType[b] == BTN_TYPE_ANALOG
|
||||
|| buttonType[b] == BTN_TYPE_ANALOG_INVERTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned long now = millis();
|
||||
static bool buttonPressedBefore = false;
|
||||
static bool buttonLongPressed = false;
|
||||
static unsigned long buttonPressedTime = 0;
|
||||
static unsigned long buttonWaitTime = 0;
|
||||
bool handled = true;
|
||||
|
||||
//momentary button logic
|
||||
if (isButtonPressed(b)) { //pressed
|
||||
|
||||
if (!buttonPressedBefore) buttonPressedTime = now;
|
||||
buttonPressedBefore = true;
|
||||
|
||||
if (now - buttonPressedTime > 600) { //long press
|
||||
buttonLongPressed = true;
|
||||
//TODO: handleButton() handles button 0 without preset in a different way for double click
|
||||
//so we need to override with same behaviour
|
||||
longPressAction(0);
|
||||
//handled = false;
|
||||
}
|
||||
|
||||
} else if (!isButtonPressed(b) && buttonPressedBefore) { //released
|
||||
|
||||
long dur = now - buttonPressedTime;
|
||||
if (dur < 50) {
|
||||
buttonPressedBefore = false;
|
||||
return true;
|
||||
} //too short "press", debounce
|
||||
|
||||
bool doublePress = buttonWaitTime; //did we have short press before?
|
||||
buttonWaitTime = 0;
|
||||
|
||||
if (!buttonLongPressed) { //short press
|
||||
// if this is second release within 350ms it is a double press (buttonWaitTime!=0)
|
||||
//TODO: handleButton() handles button 0 without preset in a different way for double click
|
||||
if (doublePress) {
|
||||
networkOverlay(PSTR("NETWORK INFO"),7000);
|
||||
handled = true;
|
||||
} else {
|
||||
buttonWaitTime = now;
|
||||
}
|
||||
}
|
||||
buttonPressedBefore = false;
|
||||
buttonLongPressed = false;
|
||||
}
|
||||
// if 350ms elapsed since last press/release it is a short press
|
||||
if (buttonWaitTime && now - buttonWaitTime > 350 && !buttonPressedBefore) {
|
||||
buttonWaitTime = 0;
|
||||
//TODO: handleButton() handles button 0 without preset in a different way for double click
|
||||
//so we need to override with same behaviour
|
||||
shortPressAction(0);
|
||||
//handled = false;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
/*
|
||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
||||
@ -846,6 +965,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
top["help4Type"] = F("1=SSD1306,2=SH1106,3=SSD1306_128x64,4=SSD1305,5=SSD1305_128x64,6=SSD1306_SPI,7=SSD1306_SPI_128x64"); // help for Settings page
|
||||
top[FPSTR(_flip)] = (bool) flip;
|
||||
top[FPSTR(_contrast)] = contrast;
|
||||
top[FPSTR(_contrastFix)] = (bool) contrastFix;
|
||||
top[FPSTR(_refreshRate)] = refreshRate;
|
||||
top[FPSTR(_screenTimeOut)] = screenTimeout/1000;
|
||||
top[FPSTR(_sleepMode)] = (bool) sleepMode;
|
||||
@ -886,6 +1006,7 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
sleepMode = top[FPSTR(_sleepMode)] | sleepMode;
|
||||
clockMode = top[FPSTR(_clockMode)] | clockMode;
|
||||
showSeconds = top[FPSTR(_showSeconds)] | showSeconds;
|
||||
contrastFix = top[FPSTR(_contrastFix)] | contrastFix;
|
||||
if (newType == SSD1306_SPI || newType == SSD1306_SPI64)
|
||||
ioFrequency = min(20000, max(500, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency
|
||||
else
|
||||
@ -914,16 +1035,18 @@ class FourLineDisplayUsermod : public Usermod {
|
||||
} else type = newType;
|
||||
setup();
|
||||
needsRedraw |= true;
|
||||
} else {
|
||||
u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||
setVcomh(contrastFix);
|
||||
setContrast(contrast);
|
||||
setFlipMode(flip);
|
||||
}
|
||||
u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||
setContrast(contrast);
|
||||
setFlipMode(flip);
|
||||
knownHour = 99;
|
||||
if (needsRedraw && !wakeDisplay()) redraw(true);
|
||||
else overlayLogo(3500);
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return !top[FPSTR(_refreshRate)].isNull();
|
||||
return !top[FPSTR(_contrastFix)].isNull();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -946,3 +1069,4 @@ const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode";
|
||||
const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode";
|
||||
const char FourLineDisplayUsermod::_showSeconds[] PROGMEM = "showSeconds";
|
||||
const char FourLineDisplayUsermod::_busClkFrequency[] PROGMEM = "i2c-freq-kHz";
|
||||
const char FourLineDisplayUsermod::_contrastFix[] PROGMEM = "contrastFix";
|
||||
|
@ -47,7 +47,7 @@
|
||||
|
||||
// The last UI state, remove color and saturation option if diplay not active(too many options)
|
||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||
#define LAST_UI_STATE 7
|
||||
#define LAST_UI_STATE 8
|
||||
#else
|
||||
#define LAST_UI_STATE 4
|
||||
#endif
|
||||
@ -160,9 +160,14 @@ private:
|
||||
uint8_t knownMode = 0;
|
||||
uint8_t knownPalette = 0;
|
||||
|
||||
uint8_t currentCCT = 128;
|
||||
bool isRgbw = false;
|
||||
|
||||
byte presetHigh = 0;
|
||||
byte presetLow = 0;
|
||||
|
||||
bool applyToAll = true;
|
||||
|
||||
bool initDone = false;
|
||||
bool enabled = true;
|
||||
|
||||
@ -174,6 +179,7 @@ private:
|
||||
static const char _SW_pin[];
|
||||
static const char _presetHigh[];
|
||||
static const char _presetLow[];
|
||||
static const char _applyToAll[];
|
||||
|
||||
/**
|
||||
* Sort the modes and palettes to the index arrays
|
||||
@ -276,6 +282,14 @@ public:
|
||||
pinMode(pinC, INPUT_PULLUP);
|
||||
loopTime = millis();
|
||||
|
||||
for (uint8_t s = 0; s < busses.getNumBusses(); s++) {
|
||||
Bus *bus = busses.getBus(s);
|
||||
if (!bus || bus->getLength()==0) break;
|
||||
isRgbw |= bus->isRgbw();
|
||||
}
|
||||
|
||||
currentCCT = (approximateKelvinFromRGB(RGBW32(col[0], col[1], col[2], col[3])) - 1900) >> 5;
|
||||
|
||||
if (!initDone) sortModesAndPalettes();
|
||||
|
||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||
@ -355,11 +369,11 @@ public:
|
||||
buttonLongPressed = false;
|
||||
buttonPressedBefore = false;
|
||||
}
|
||||
if (buttonWaitTime && currentTime-buttonWaitTime>350 && !buttonPressedBefore) {
|
||||
if (buttonWaitTime && currentTime-buttonWaitTime>350 && !buttonPressedBefore) { //same speed as in button.cpp
|
||||
buttonWaitTime = 0;
|
||||
char newState = select_state + 1;
|
||||
bool changedState = true;
|
||||
if (newState > LAST_UI_STATE || (newState == 7 && presetHigh==0 && presetLow == 0)) newState = 0;
|
||||
if (newState > LAST_UI_STATE || (newState == 8 && presetHigh==0 && presetLow == 0)) newState = 0;
|
||||
if (display != nullptr) {
|
||||
switch (newState) {
|
||||
case 0: changedState = changeState(PSTR("Brightness"), 1, 0, 1); break; //1 = sun
|
||||
@ -369,7 +383,8 @@ public:
|
||||
case 4: changedState = changeState(PSTR("Effect"), 3, 0, 5); break; //5 = puzzle piece
|
||||
case 5: changedState = changeState(PSTR("Main Color"), 255, 255, 7); break; //7 = brush
|
||||
case 6: changedState = changeState(PSTR("Saturation"), 255, 255, 8); break; //8 = contrast
|
||||
case 7: changedState = changeState(PSTR("Preset"), 255, 255, 11); break; //11 = heart
|
||||
case 7: changedState = changeState(PSTR("CCT"), 255, 255, 10); break; //10 = star
|
||||
case 8: changedState = changeState(PSTR("Preset"), 255, 255, 11); break; //11 = heart
|
||||
}
|
||||
}
|
||||
if (changedState) select_state = newState;
|
||||
@ -389,7 +404,8 @@ public:
|
||||
case 4: changeEffect(true); break;
|
||||
case 5: changeHue(true); break;
|
||||
case 6: changeSat(true); break;
|
||||
case 7: changePreset(true); break;
|
||||
case 7: changeCCT(true); break;
|
||||
case 8: changePreset(true); break;
|
||||
}
|
||||
}
|
||||
else if (Enc_B == HIGH)
|
||||
@ -402,7 +418,8 @@ public:
|
||||
case 4: changeEffect(false); break;
|
||||
case 5: changeHue(false); break;
|
||||
case 6: changeSat(false); break;
|
||||
case 7: changePreset(false); break;
|
||||
case 7: changeCCT(false); break;
|
||||
case 8: changePreset(false); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -452,6 +469,7 @@ public:
|
||||
//bool fxChanged = strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectPalette);
|
||||
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
||||
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
|
||||
setValuesFromMainSeg(); //to make transition work on main segment
|
||||
colorUpdated(CALL_MODE_DIRECT_CHANGE);
|
||||
updateInterfaces(CALL_MODE_DIRECT_CHANGE);
|
||||
}
|
||||
@ -463,6 +481,7 @@ public:
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
display->updateRedrawTime();
|
||||
#endif
|
||||
bri = max(min((increase ? bri+fadeAmount : bri-fadeAmount), 255), 0);
|
||||
lampUdated();
|
||||
@ -479,9 +498,21 @@ public:
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
display->updateRedrawTime();
|
||||
#endif
|
||||
effectCurrentIndex = max(min((increase ? effectCurrentIndex+1 : effectCurrentIndex-1), strip.getModeCount()-1), 0);
|
||||
effectCurrent = modes_alpha_indexes[effectCurrentIndex];
|
||||
effectChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
strip.setMode(i, effectCurrent);
|
||||
}
|
||||
} else {
|
||||
//WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
strip.setMode(strip.getMainSegmentId(), effectCurrent);
|
||||
}
|
||||
lampUdated();
|
||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||
display->showCurrentEffectOrPalette(effectCurrent, JSON_mode_names, 3);
|
||||
@ -496,8 +527,20 @@ public:
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
display->updateRedrawTime();
|
||||
#endif
|
||||
effectSpeed = max(min((increase ? effectSpeed+fadeAmount : effectSpeed-fadeAmount), 255), 0);
|
||||
effectChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.speed = effectSpeed;
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.speed = effectSpeed;
|
||||
}
|
||||
lampUdated();
|
||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||
display->updateSpeed();
|
||||
@ -512,8 +555,20 @@ public:
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
display->updateRedrawTime();
|
||||
#endif
|
||||
effectIntensity = max(min((increase ? effectIntensity+fadeAmount : effectIntensity-fadeAmount), 255), 0);
|
||||
effectChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.intensity = effectIntensity;
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.intensity = effectIntensity;
|
||||
}
|
||||
lampUdated();
|
||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||
display->updateIntensity();
|
||||
@ -528,9 +583,21 @@ public:
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
display->updateRedrawTime();
|
||||
#endif
|
||||
effectPaletteIndex = max(min((increase ? effectPaletteIndex+1 : effectPaletteIndex-1), strip.getPaletteCount()-1), 0);
|
||||
effectPalette = palettes_alpha_indexes[effectPaletteIndex];
|
||||
effectChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.palette = effectPalette;
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.palette = effectPalette;
|
||||
}
|
||||
lampUdated();
|
||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||
display->showCurrentEffectOrPalette(effectPalette, JSON_palette_names, 2);
|
||||
@ -545,15 +612,22 @@ public:
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
display->updateRedrawTime();
|
||||
#endif
|
||||
currentHue1 = max(min((increase ? currentHue1+fadeAmount : currentHue1-fadeAmount), 255), 0);
|
||||
colorHStoRGB(currentHue1*256, currentSat1, col);
|
||||
strip.applyToAllSelected = true;
|
||||
strip.setColor(0, colorFromRgbw(col));
|
||||
colorChanged = true;
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
}
|
||||
lampUdated();
|
||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||
display->updateRedrawTime();
|
||||
#endif
|
||||
}
|
||||
|
||||
void changeSat(bool increase){
|
||||
@ -563,15 +637,21 @@ public:
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
display->updateRedrawTime();
|
||||
#endif
|
||||
currentSat1 = max(min((increase ? currentSat1+fadeAmount : currentSat1-fadeAmount), 255), 0);
|
||||
colorHStoRGB(currentHue1*256, currentSat1, col);
|
||||
strip.applyToAllSelected = true;
|
||||
strip.setColor(0, colorFromRgbw(col));
|
||||
if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
}
|
||||
} else {
|
||||
WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
}
|
||||
lampUdated();
|
||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||
display->updateRedrawTime();
|
||||
#endif
|
||||
}
|
||||
|
||||
void changePreset(bool increase) {
|
||||
@ -581,6 +661,7 @@ public:
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
display->updateRedrawTime();
|
||||
#endif
|
||||
if (presetHigh && presetLow && presetHigh > presetLow) {
|
||||
String apireq = F("win&PL=~");
|
||||
@ -592,9 +673,29 @@ public:
|
||||
handleSet(nullptr, apireq, false);
|
||||
lampUdated();
|
||||
}
|
||||
}
|
||||
|
||||
void changeCCT(bool increase){
|
||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||
if (display && display->wakeDisplay()) {
|
||||
display->redraw(true);
|
||||
// Throw away wake up input
|
||||
return;
|
||||
}
|
||||
display->updateRedrawTime();
|
||||
#endif
|
||||
currentCCT = max(min((increase ? currentCCT+fadeAmount : currentCCT-fadeAmount), 255), 0);
|
||||
// if (applyToAll) {
|
||||
for (byte i=0; i<strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive()) continue;
|
||||
seg.setCCT(currentCCT, i);
|
||||
}
|
||||
// } else {
|
||||
// WS2812FX::Segment& seg = strip.getSegment(strip.getMainSegmentId());
|
||||
// seg.setCCT(currentCCT, strip.getMainSegmentId());
|
||||
// }
|
||||
lampUdated();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -650,6 +751,7 @@ public:
|
||||
top[FPSTR(_SW_pin)] = pinC;
|
||||
top[FPSTR(_presetLow)] = presetLow;
|
||||
top[FPSTR(_presetHigh)] = presetHigh;
|
||||
top[FPSTR(_applyToAll)] = applyToAll;
|
||||
DEBUG_PRINTLN(F("Rotary Encoder config saved."));
|
||||
}
|
||||
|
||||
@ -676,6 +778,7 @@ public:
|
||||
presetLow = MIN(250,MAX(0,presetLow));
|
||||
|
||||
enabled = top[FPSTR(_enabled)] | enabled;
|
||||
applyToAll = top[FPSTR(_applyToAll)] | applyToAll;
|
||||
|
||||
DEBUG_PRINT(FPSTR(_name));
|
||||
if (!initDone) {
|
||||
@ -702,7 +805,7 @@ public:
|
||||
}
|
||||
}
|
||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||
return !top[FPSTR(_presetHigh)].isNull();
|
||||
return !top[FPSTR(_applyToAll)].isNull();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -723,3 +826,4 @@ const char RotaryEncoderUIUsermod::_CLK_pin[] PROGMEM = "CLK-pin";
|
||||
const char RotaryEncoderUIUsermod::_SW_pin[] PROGMEM = "SW-pin";
|
||||
const char RotaryEncoderUIUsermod::_presetHigh[] PROGMEM = "preset-high";
|
||||
const char RotaryEncoderUIUsermod::_presetLow[] PROGMEM = "preset-low";
|
||||
const char RotaryEncoderUIUsermod::_applyToAll[] PROGMEM = "apply-2-all-seg";
|
||||
|
@ -390,7 +390,7 @@ uint8_t WS2812FX::getPaletteCount()
|
||||
|
||||
//TODO effect transitions
|
||||
|
||||
|
||||
/*
|
||||
bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) {
|
||||
Segment& seg = _segments[getMainSegmentId()];
|
||||
uint8_t modePrev = seg.mode, speedPrev = seg.speed, intensityPrev = seg.intensity, palettePrev = seg.palette;
|
||||
@ -425,7 +425,7 @@ bool WS2812FX::setEffectConfig(uint8_t m, uint8_t s, uint8_t in, uint8_t p) {
|
||||
void WS2812FX::setColor(uint8_t slot, uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
|
||||
setColor(slot, RGBW32(r, g, b, w));
|
||||
}
|
||||
|
||||
*/
|
||||
void WS2812FX::setColor(uint8_t slot, uint32_t c) {
|
||||
if (slot >= NUM_COLORS) return;
|
||||
|
||||
|
@ -257,6 +257,7 @@ void handleButton()
|
||||
if (b == 0 && dur > WLED_LONG_AP) { //long press on button 0 (when released)
|
||||
WLED::instance().initAP(true);
|
||||
} else if (!buttonLongPressed[b]) { //short press
|
||||
//NOTE: this interferes with double click handling in usermods so it is commented out
|
||||
if (b == 0 && !macroDoublePress[b]) { //don't wait for double press on button 0 if no double press macro set
|
||||
shortPressAction(b);
|
||||
} else { //double press if less than 350 ms between current press and previous short press release (buttonWaitTime!=0)
|
||||
|
@ -22,11 +22,6 @@ void colorFromUint24(uint32_t in, bool secondary)
|
||||
_col[2] = B(in);
|
||||
}
|
||||
|
||||
//store color components in uint32_t
|
||||
uint32_t colorFromRgbw(byte* rgbw) {
|
||||
return RGBW32(rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
|
||||
}
|
||||
|
||||
//relatively change white brightness, minumum A=5
|
||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary)
|
||||
{
|
||||
@ -259,7 +254,7 @@ uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb)
|
||||
rgbw[1] = ((uint16_t) correctionRGB[1] * G(rgb)) /255; // correct G
|
||||
rgbw[2] = ((uint16_t) correctionRGB[2] * B(rgb)) /255; // correct B
|
||||
rgbw[3] = W(rgb);
|
||||
return colorFromRgbw(rgbw);
|
||||
return RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]);
|
||||
}
|
||||
|
||||
//approximates a Kelvin color temperature from an RGB color.
|
||||
|
@ -38,12 +38,17 @@
|
||||
l.addEventListener('load', (e) => {
|
||||
// after rangetouch is loaded initialize global variable
|
||||
ranges = RangeTouch.setup('input[type="range"]', {});
|
||||
onLoad(); // start processing UI
|
||||
let stateCheck = setInterval(() => {
|
||||
if (document.readyState === 'complete') {
|
||||
clearInterval(stateCheck);
|
||||
// document ready, start processing UI
|
||||
onLoad();
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
//h.appendChild(l); // if this fires too quickly for ESP8266 use next line
|
||||
setTimeout(function(){h.appendChild(l)},50);
|
||||
setTimeout(()=>{h.appendChild(l)},50);
|
||||
});
|
||||
setTimeout(function(){h.appendChild(l)},50);
|
||||
setTimeout(()=>{h.appendChild(l)},50);
|
||||
</script>
|
||||
<link rel="stylesheet" href="index.css">
|
||||
</head>
|
||||
|
@ -10,7 +10,6 @@ var nlDur = 60, nlTar = 0;
|
||||
var nlMode = false;
|
||||
var selectedFx = 0, prevFx = -1;
|
||||
var selectedPal = 0;
|
||||
var sliderControl = ""; //WLEDSR: used by togglePcMode
|
||||
var csel = 0;
|
||||
var currentPreset = -1, prevPS = -1;
|
||||
var lastUpdate = 0;
|
||||
@ -1614,6 +1613,11 @@ ${makePlSel(true)}
|
||||
Save segment bounds
|
||||
<input type="checkbox" id="p${i}sbtgl" checked>
|
||||
<span class="checkmark schk"></span>
|
||||
</label>
|
||||
<label class="check revchkl">
|
||||
Checked segments only
|
||||
<input type="checkbox" id="p${i}sbchk">
|
||||
<span class="checkmark schk"></span>
|
||||
</label>`;
|
||||
|
||||
return `<input type="text" class="ptxt noslide" id="p${i}txt" autocomplete="off" maxlength=32 value="${(i>0)?pName(i):""}" placeholder="Enter name..."/>
|
||||
@ -1911,6 +1915,7 @@ function saveP(i,pl)
|
||||
} else {
|
||||
obj.ib = gId(`p${i}ibtgl`).checked;
|
||||
obj.sb = gId(`p${i}sbtgl`).checked;
|
||||
obj.sc = gId(`p${i}sbchk`).checked;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2091,8 +2096,15 @@ function setBalance(b)
|
||||
}
|
||||
|
||||
var hc = 0;
|
||||
setInterval(()=>{if (!isInfo) return; hc+=18; if (hc>300) hc=0; if (hc>200)hc=306; if (hc==144) hc+=36; if (hc==108) hc+=18;
|
||||
gId('heart').style.color = `hsl(${hc}, 100%, 50%)`;}, 910);
|
||||
setInterval(()=>{
|
||||
if (!isInfo) return;
|
||||
hc+=18;
|
||||
if (hc>300) hc=0;
|
||||
if (hc>200)hc=306;
|
||||
if (hc==144) hc+=36;
|
||||
if (hc==108) hc+=18;
|
||||
gId('heart').style.color = `hsl(${hc}, 100%, 50%)`;
|
||||
}, 910);
|
||||
|
||||
function openGH() { window.open("https://github.com/Aircoookie/WLED/wiki"); }
|
||||
|
||||
@ -2361,7 +2373,7 @@ function togglePcMode(fromB = false)
|
||||
if (wW < 1250 && !pcMode) return;
|
||||
if (!fromB && ((wW < 1250 && lastw < 1250) || (wW >= 1250 && lastw >= 1250))) return;
|
||||
openTab(0, true);
|
||||
if (w < 1250) {pcMode = false;}
|
||||
if (wW < 1250) {pcMode = false;}
|
||||
else if (pcModeA && !fromB) pcMode = pcModeA;
|
||||
updateTablinks(0);
|
||||
gId('buttonPcm').className = (pcMode) ? "active":"";
|
||||
|
@ -23,6 +23,8 @@ void updateBlynk();
|
||||
|
||||
//button.cpp
|
||||
void shortPressAction(uint8_t b=0);
|
||||
void longPressAction(uint8_t b=0);
|
||||
void doublePressAction(uint8_t b=0);
|
||||
bool isButtonPressed(uint8_t b=0);
|
||||
void handleButton();
|
||||
void handleIO();
|
||||
@ -58,7 +60,7 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau
|
||||
//colors.cpp
|
||||
void colorFromUint32(uint32_t in, bool secondary = false);
|
||||
void colorFromUint24(uint32_t in, bool secondary = false);
|
||||
uint32_t colorFromRgbw(byte* rgbw);
|
||||
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0);
|
||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
||||
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
||||
@ -146,7 +148,6 @@ void resetTimebase();
|
||||
void toggleOnOff();
|
||||
void setAllLeds();
|
||||
void setLedsStandard();
|
||||
bool colorChanged();
|
||||
void colorUpdated(int callMode);
|
||||
void updateInterfaces(uint8_t callMode);
|
||||
void handleTransitions();
|
||||
|
3112
wled00/html_ui.h
3112
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -131,14 +131,11 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
}
|
||||
|
||||
if (!colValid) continue;
|
||||
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
||||
{
|
||||
if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
|
||||
if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];}
|
||||
} else { //normal case, apply directly to segment
|
||||
seg.setColor(i, ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF))), id);
|
||||
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
|
||||
}
|
||||
|
||||
uint32_t color = RGBW32(rgbw[0],rgbw[1],rgbw[2],rgbw[3]);
|
||||
colorChanged |= (seg.colors[i] != color);
|
||||
seg.setColor(i, color, id);
|
||||
if (seg.mode == FX_MODE_STATIC) strip.trigger(); //instant refresh
|
||||
}
|
||||
}
|
||||
|
||||
@ -161,26 +158,18 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
||||
|
||||
if (!(elem[F("sel")].isNull() && elem["rev"].isNull() && elem["on"].isNull() && elem[F("mi")].isNull())) effectChanged = true; //send UDP
|
||||
|
||||
//temporary, strip object gets updated via colorUpdated()
|
||||
if (id == strip.getMainSegmentId()) {
|
||||
byte effectPrev = effectCurrent;
|
||||
if (getVal(elem["fx"], &effectCurrent, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 1-255 exact value)
|
||||
if (!presetId && effectCurrent != effectPrev) unloadPlaylist(); //stop playlist if active and FX changed manually
|
||||
}
|
||||
effectSpeed = elem[F("sx")] | effectSpeed;
|
||||
effectIntensity = elem[F("ix")] | effectIntensity;
|
||||
getVal(elem["pal"], &effectPalette, 1, strip.getPaletteCount());
|
||||
} else { //permanent
|
||||
byte fx = seg.mode;
|
||||
byte fxPrev = fx;
|
||||
if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 1-255 exact value)
|
||||
strip.setMode(id, fx);
|
||||
if (!presetId && seg.mode != fxPrev) unloadPlaylist(); //stop playlist if active and FX changed manually
|
||||
}
|
||||
seg.speed = elem[F("sx")] | seg.speed;
|
||||
seg.intensity = elem[F("ix")] | seg.intensity;
|
||||
getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount());
|
||||
byte fx = seg.mode;
|
||||
byte fxPrev = fx;
|
||||
if (getVal(elem["fx"], &fx, 1, strip.getModeCount())) { //load effect ('r' random, '~' inc/dec, 1-255 exact value)
|
||||
strip.setMode(id, fx);
|
||||
if (!presetId && seg.mode != fxPrev) effectChanged = true; //send UDP
|
||||
}
|
||||
byte prevSpd = seg.speed;
|
||||
byte prevInt = seg.intensity;
|
||||
byte prevPal = seg.palette;
|
||||
if (getVal(elem[F("sx")], &seg.speed, 0, 255) && !presetId && prevSpd != seg.speed) effectChanged = true; //also supports inc/decrementing and random
|
||||
if (getVal(elem[F("ix")], &seg.intensity, 0, 255) && !presetId && prevInt != seg.intensity) effectChanged = true; //also supports inc/decrementing and random
|
||||
if (getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount()) && !presetId && prevPal != seg.palette) effectChanged = true; //also supports inc/decrementing and random
|
||||
|
||||
JsonArray iarr = elem[F("i")]; //set individual LEDs
|
||||
if (!iarr.isNull()) {
|
||||
@ -307,32 +296,32 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
|
||||
byte prevMain = strip.getMainSegmentId();
|
||||
strip.mainSegment = root[F("mainseg")] | prevMain;
|
||||
if (strip.getMainSegmentId() != prevMain) setValuesFromMainSeg();
|
||||
//if (strip.getMainSegmentId() != prevMain) setValuesFromMainSeg();
|
||||
|
||||
int it = 0;
|
||||
JsonVariant segVar = root["seg"];
|
||||
if (segVar.is<JsonObject>())
|
||||
{
|
||||
int id = segVar["id"] | -1;
|
||||
|
||||
if (id < 0) { //set all selected segments
|
||||
bool didSet = false;
|
||||
byte lowestActive = 99;
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
||||
{
|
||||
//if "seg" is not an array and ID not specified, apply to all selected/checked segments
|
||||
if (id < 0) {
|
||||
//apply all selected segments
|
||||
//bool didSet = false;
|
||||
//byte lowestActive = 99;
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++) {
|
||||
WS2812FX::Segment &sg = strip.getSegment(s);
|
||||
if (sg.isActive())
|
||||
{
|
||||
if (lowestActive == 99) lowestActive = s;
|
||||
if (sg.isActive()) {
|
||||
//if (lowestActive == 99) lowestActive = s;
|
||||
if (sg.isSelected()) {
|
||||
deserializeSegment(segVar, s, presetId);
|
||||
didSet = true;
|
||||
//didSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!didSet && lowestActive < strip.getMaxSegments()) deserializeSegment(segVar, lowestActive, presetId);
|
||||
} else { //set only the segment with the specified ID
|
||||
deserializeSegment(segVar, it, presetId);
|
||||
//TODO: not sure if it is good idea to change first active but unselected segment
|
||||
//if (!didSet && lowestActive < strip.getMaxSegments()) deserializeSegment(segVar, lowestActive, presetId);
|
||||
} else {
|
||||
deserializeSegment(segVar, id, presetId); //apply only the segment with the specified ID
|
||||
}
|
||||
} else {
|
||||
JsonArray segs = segVar.as<JsonArray>();
|
||||
@ -342,6 +331,8 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
|
||||
it++;
|
||||
}
|
||||
}
|
||||
setValuesFromMainSeg(); //to make transition work on main segment
|
||||
if (effectChanged) unloadPlaylist(); //if any of the effect parameter changed unload playlist
|
||||
|
||||
#ifndef WLED_DISABLE_CRONIXIE
|
||||
if (root["nx"].is<const char*>()) {
|
||||
@ -437,12 +428,12 @@ void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id, bool fo
|
||||
strcat_P(colstr, PSTR("]"));
|
||||
root["col"] = serialized(colstr);
|
||||
|
||||
root["fx"] = seg.mode;
|
||||
root["fx"] = seg.mode;
|
||||
root[F("sx")] = seg.speed;
|
||||
root[F("ix")] = seg.intensity;
|
||||
root["pal"] = seg.palette;
|
||||
root["pal"] = seg.palette;
|
||||
root[F("sel")] = seg.isSelected();
|
||||
root["rev"] = seg.getOption(SEG_OPTION_REVERSED);
|
||||
root["rev"] = seg.getOption(SEG_OPTION_REVERSED);
|
||||
root[F("mi")] = seg.getOption(SEG_OPTION_MIRROR);
|
||||
}
|
||||
|
||||
@ -483,12 +474,12 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
|
||||
|
||||
root[F("mainseg")] = strip.getMainSegmentId();
|
||||
|
||||
bool selectedSegmentsOnly = root[F("sc")] | false;
|
||||
JsonArray seg = root.createNestedArray("seg");
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
||||
{
|
||||
for (byte s = 0; s < strip.getMaxSegments(); s++) {
|
||||
WS2812FX::Segment &sg = strip.getSegment(s);
|
||||
if (sg.isActive())
|
||||
{
|
||||
if (selectedSegmentsOnly && !sg.isSelected()) continue;
|
||||
if (sg.isActive()) {
|
||||
JsonObject seg0 = seg.createNestedObject();
|
||||
serializeSegment(seg0, sg, s, forPreset, segmentBounds);
|
||||
} else if (forPreset && segmentBounds) { //disable segments not part of preset
|
||||
|
@ -44,8 +44,8 @@ byte scaledBri(byte in)
|
||||
|
||||
|
||||
void setAllLeds() {
|
||||
strip.setColor(0, col[0], col[1], col[2], col[3]);
|
||||
strip.setColor(1, colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||
strip.setColor(0, RGBW32(col[0], col[1], col[2], col[3]));
|
||||
strip.setColor(1, RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]));
|
||||
if (!realtimeMode || !arlsForceMaxBri)
|
||||
{
|
||||
strip.setBrightness(scaledBri(briT));
|
||||
@ -61,106 +61,67 @@ void setLedsStandard()
|
||||
}
|
||||
|
||||
|
||||
bool colorChanged()
|
||||
{
|
||||
for (byte i=0; i<4; i++)
|
||||
{
|
||||
if (col[i] != colIT[i]) return true;
|
||||
if (colSec[i] != colSecIT[i]) return true;
|
||||
}
|
||||
if (bri != briIT) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void colorUpdated(int callMode)
|
||||
{
|
||||
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
||||
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa 11: ws send only 12: button preset
|
||||
if (callMode != CALL_MODE_INIT &&
|
||||
callMode != CALL_MODE_DIRECT_CHANGE &&
|
||||
callMode != CALL_MODE_NO_NOTIFY &&
|
||||
callMode != CALL_MODE_BUTTON_PRESET) strip.applyToAllSelected = true; //if not from JSON api, which directly sets segments
|
||||
|
||||
bool someSel = false;
|
||||
|
||||
if (callMode == CALL_MODE_NOTIFICATION) {
|
||||
someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects || receiveSegmentOptions);
|
||||
}
|
||||
|
||||
//Notifier: apply received FX to selected segments only if actually receiving FX
|
||||
if (someSel) strip.applyToAllSelected = receiveNotificationEffects;
|
||||
|
||||
bool fxChanged = strip.setEffectConfig(effectCurrent, effectSpeed, effectIntensity, effectPalette) || effectChanged;
|
||||
bool colChanged = colorChanged();
|
||||
|
||||
//Notifier: apply received color to selected segments only if actually receiving color
|
||||
if (someSel) strip.applyToAllSelected = receiveNotificationColor;
|
||||
|
||||
if (fxChanged || colChanged)
|
||||
{
|
||||
effectChanged = false;
|
||||
if (bri != briOld || effectChanged || colorChanged) {
|
||||
if (realtimeTimeout == UINT32_MAX) realtimeTimeout = 0;
|
||||
currentPreset = 0; //something changed, so we are no longer in the preset
|
||||
if (effectChanged) currentPreset = 0; //something changed, so we are no longer in the preset
|
||||
|
||||
notify(callMode);
|
||||
if (callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) notify(callMode);
|
||||
|
||||
//set flag to update blynk, ws and mqtt
|
||||
interfaceUpdateCallMode = callMode;
|
||||
effectChanged = false;
|
||||
colorChanged = false;
|
||||
} else {
|
||||
if (nightlightActive && !nightlightActiveOld &&
|
||||
callMode != CALL_MODE_NOTIFICATION &&
|
||||
callMode != CALL_MODE_NO_NOTIFY)
|
||||
{
|
||||
if (nightlightActive && !nightlightActiveOld && callMode != CALL_MODE_NOTIFICATION && callMode != CALL_MODE_NO_NOTIFY) {
|
||||
notify(CALL_MODE_NIGHTLIGHT);
|
||||
interfaceUpdateCallMode = CALL_MODE_NIGHTLIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
if (!colChanged) return; //following code is for e.g. initiating transitions
|
||||
|
||||
if (callMode != CALL_MODE_NO_NOTIFY && nightlightActive && (nightlightMode == NL_MODE_FADE || nightlightMode == NL_MODE_COLORFADE))
|
||||
{
|
||||
if (callMode != CALL_MODE_NO_NOTIFY && nightlightActive && (nightlightMode == NL_MODE_FADE || nightlightMode == NL_MODE_COLORFADE)) {
|
||||
briNlT = bri;
|
||||
nightlightDelayMs -= (millis() - nightlightStartTime);
|
||||
nightlightStartTime = millis();
|
||||
}
|
||||
for (byte i=0; i<4; i++)
|
||||
{
|
||||
colIT[i] = col[i];
|
||||
colSecIT[i] = colSec[i];
|
||||
}
|
||||
if (briT == 0)
|
||||
{
|
||||
if (briT == 0) {
|
||||
if (callMode != CALL_MODE_NOTIFICATION) resetTimebase(); //effect start from beginning
|
||||
}
|
||||
|
||||
briIT = bri;
|
||||
if (bri > 0) briLast = bri;
|
||||
|
||||
//deactivate nightlight if target brightness is reached
|
||||
if (bri == nightlightTargetBri && callMode != CALL_MODE_NO_NOTIFY && nightlightMode != NL_MODE_SUN) nightlightActive = false;
|
||||
|
||||
if (fadeTransition)
|
||||
{
|
||||
if (fadeTransition) {
|
||||
//set correct delay if not using notification delay
|
||||
if (callMode != CALL_MODE_NOTIFICATION && !jsonTransitionOnce) transitionDelayTemp = transitionDelay;
|
||||
jsonTransitionOnce = false;
|
||||
strip.setTransition(transitionDelayTemp);
|
||||
if (transitionDelayTemp == 0) {setLedsStandard(); strip.trigger(); return;}
|
||||
|
||||
if (transitionActive)
|
||||
{
|
||||
if (transitionDelayTemp == 0) {
|
||||
//setLedsStandard();
|
||||
briOld = briT = bri;
|
||||
if (!realtimeMode || !arlsForceMaxBri) strip.setBrightness(scaledBri(briT));
|
||||
strip.trigger();
|
||||
return;
|
||||
}
|
||||
|
||||
if (transitionActive) {
|
||||
briOld = briT;
|
||||
tperLast = 0;
|
||||
}
|
||||
strip.setTransitionMode(true);
|
||||
transitionActive = true;
|
||||
transitionStartTime = millis();
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
strip.setTransition(0);
|
||||
setLedsStandard();
|
||||
//setLedsStandard();
|
||||
briOld = briT = bri;
|
||||
if (!realtimeMode || !arlsForceMaxBri) strip.setBrightness(scaledBri(briT));
|
||||
strip.trigger();
|
||||
}
|
||||
}
|
||||
@ -218,6 +179,12 @@ void handleTransitions()
|
||||
|
||||
void handleNightlight()
|
||||
{
|
||||
static unsigned long lastNlUpdate;
|
||||
unsigned long now = millis();
|
||||
if (now < 100 && lastNlUpdate > 0) lastNlUpdate = 0; //take care of millis() rollover
|
||||
if (now - lastNlUpdate < 100) return; //allow only 10 NL updates per second
|
||||
lastNlUpdate = now;
|
||||
|
||||
if (nightlightActive)
|
||||
{
|
||||
if (!nightlightActiveOld) //init
|
||||
|
@ -63,7 +63,6 @@ void handlePresets()
|
||||
|
||||
if (!errorFlag && presetToApply < 255) currentPreset = presetToApply;
|
||||
|
||||
effectChanged = true; //force UDP notification
|
||||
colorUpdated(callModeToApply);
|
||||
updateInterfaces(callModeToApply);
|
||||
|
||||
@ -102,6 +101,7 @@ void savePreset(byte index, bool persist, const char* pname, JsonObject saveobj)
|
||||
sObj.remove("o");
|
||||
sObj.remove("ib");
|
||||
sObj.remove("sb");
|
||||
sObj.remove(F("sc"));
|
||||
sObj.remove(F("error"));
|
||||
sObj.remove(F("time"));
|
||||
|
||||
|
132
wled00/set.cpp
132
wled00/set.cpp
@ -532,7 +532,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
DEBUG_PRINT(F("API req: "));
|
||||
DEBUG_PRINTLN(req);
|
||||
|
||||
strip.applyToAllSelected = false;
|
||||
strip.applyToAllSelected = true;
|
||||
|
||||
//segment select (sets main segment)
|
||||
byte prevMain = strip.getMainSegmentId();
|
||||
@ -543,22 +543,28 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
byte selectedSeg = strip.getMainSegmentId();
|
||||
if (selectedSeg != prevMain) setValuesFromMainSeg();
|
||||
|
||||
//snapshot to check if request changed values later, temporary.
|
||||
byte prevCol[4] = {col[0], col[1], col[2], col[3]};
|
||||
byte prevColSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]};
|
||||
byte prevEffect = effectCurrent;
|
||||
byte prevSpeed = effectSpeed;
|
||||
byte prevIntensity = effectIntensity;
|
||||
byte prevPalette = effectPalette;
|
||||
|
||||
pos = req.indexOf(F("SS="));
|
||||
if (pos > 0) {
|
||||
byte t = getNumVal(&req, pos);
|
||||
if (t < strip.getMaxSegments()) selectedSeg = t;
|
||||
if (t < strip.getMaxSegments()) {
|
||||
selectedSeg = t;
|
||||
strip.applyToAllSelected = false;
|
||||
}
|
||||
}
|
||||
|
||||
WS2812FX::Segment& selseg = strip.getSegment(selectedSeg);
|
||||
pos = req.indexOf(F("SV=")); //segment selected
|
||||
if (pos > 0) {
|
||||
byte t = getNumVal(&req, pos);
|
||||
if (t == 2) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++)
|
||||
{
|
||||
strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0);
|
||||
}
|
||||
}
|
||||
if (t == 2) for (uint8_t i = 0; i < strip.getMaxSegments(); i++) strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0); // unselect other segments
|
||||
selseg.setOption(SEG_OPTION_SELECTED, t);
|
||||
}
|
||||
|
||||
@ -624,26 +630,21 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
applyPreset(presetCycCurr);
|
||||
}
|
||||
|
||||
//snapshot to check if request changed values later, temporary.
|
||||
byte prevCol[4] = {col[0], col[1], col[2], col[3]};
|
||||
byte prevColSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]};
|
||||
byte prevEffect = effectCurrent;
|
||||
byte prevSpeed = effectSpeed;
|
||||
byte prevIntensity = effectIntensity;
|
||||
byte prevPalette = effectPalette;
|
||||
|
||||
//set brightness
|
||||
updateVal(&req, "&A=", &bri);
|
||||
|
||||
bool col0Changed = false, col1Changed = false, col2Changed = false;
|
||||
//set colors
|
||||
updateVal(&req, "&R=", &col[0]);
|
||||
updateVal(&req, "&G=", &col[1]);
|
||||
updateVal(&req, "&B=", &col[2]);
|
||||
updateVal(&req, "&W=", &col[3]);
|
||||
for (byte i=0; i<4; i++) if (prevCol[i]!=col[i]) col0Changed = colorChanged = true;
|
||||
updateVal(&req, "R2=", &colSec[0]);
|
||||
updateVal(&req, "G2=", &colSec[1]);
|
||||
updateVal(&req, "B2=", &colSec[2]);
|
||||
updateVal(&req, "W2=", &colSec[3]);
|
||||
for (byte i=0; i<4; i++) if (prevColSec[i]!=colSec[i]) col1Changed = colorChanged = true;
|
||||
|
||||
#ifdef WLED_ENABLE_LOXONE
|
||||
//lox parser
|
||||
@ -674,52 +675,64 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
if (pos > 0) {
|
||||
tempsat = getNumVal(&req, pos);
|
||||
}
|
||||
colorHStoRGB(temphue,tempsat,(req.indexOf(F("H2"))>0)? colSec:col);
|
||||
byte sec = req.indexOf(F("H2"));
|
||||
colorHStoRGB(temphue, tempsat, (sec>0) ? colSec : col);
|
||||
if (sec>0) col1Changed = true;
|
||||
else col0Changed = true;
|
||||
colorChanged = true;
|
||||
}
|
||||
|
||||
//set white spectrum (kelvin)
|
||||
pos = req.indexOf(F("&K="));
|
||||
if (pos > 0) {
|
||||
colorKtoRGB(getNumVal(&req, pos),(req.indexOf(F("K2"))>0)? colSec:col);
|
||||
byte sec = req.indexOf(F("K2"));
|
||||
colorKtoRGB(getNumVal(&req, pos), (sec>0) ? colSec : col);
|
||||
if (sec>0) col1Changed = true;
|
||||
else col0Changed = true;
|
||||
colorChanged = true;
|
||||
}
|
||||
|
||||
//set color from HEX or 32bit DEC
|
||||
byte tmpCol[4];
|
||||
pos = req.indexOf(F("CL="));
|
||||
if (pos > 0) {
|
||||
colorFromDecOrHexString(col, (char*)req.substring(pos + 3).c_str());
|
||||
selseg.setColor(0, RGBW32(col[0], col[1], col[2], col[3]), selectedSeg); // defined above (SS= or main)
|
||||
col0Changed = colorChanged = true;
|
||||
}
|
||||
pos = req.indexOf(F("C2="));
|
||||
if (pos > 0) {
|
||||
colorFromDecOrHexString(colSec, (char*)req.substring(pos + 3).c_str());
|
||||
selseg.setColor(1, RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]), selectedSeg); // defined above (SS= or main)
|
||||
col1Changed = colorChanged = true;
|
||||
}
|
||||
pos = req.indexOf(F("C3="));
|
||||
if (pos > 0) {
|
||||
byte t[4];
|
||||
colorFromDecOrHexString(t, (char*)req.substring(pos + 3).c_str());
|
||||
if (selectedSeg != strip.getMainSegmentId()) {
|
||||
strip.applyToAllSelected = true;
|
||||
strip.setColor(2, t[0], t[1], t[2], t[3]);
|
||||
} else {
|
||||
selseg.setColor(2, RGBW32(t[0], t[1], t[2], t[3]), selectedSeg); // defined above (SS=)
|
||||
}
|
||||
colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str());
|
||||
selseg.setColor(2, RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]), selectedSeg); // defined above (SS= or main)
|
||||
col2Changed = colorChanged = true;
|
||||
}
|
||||
|
||||
//set to random hue SR=0->1st SR=1->2nd
|
||||
pos = req.indexOf(F("SR"));
|
||||
if (pos > 0) {
|
||||
_setRandomColor(getNumVal(&req, pos));
|
||||
byte sec = getNumVal(&req, pos);
|
||||
_setRandomColor(sec);
|
||||
if (sec>0) col1Changed = true;
|
||||
else col0Changed = true;
|
||||
colorChanged = true;
|
||||
}
|
||||
|
||||
//swap 2nd & 1st
|
||||
pos = req.indexOf(F("SC"));
|
||||
if (pos > 0) {
|
||||
byte temp;
|
||||
for (uint8_t i=0; i<4; i++)
|
||||
{
|
||||
temp = col[i];
|
||||
col[i] = colSec[i];
|
||||
for (uint8_t i=0; i<4; i++) {
|
||||
temp = col[i];
|
||||
col[i] = colSec[i];
|
||||
colSec[i] = temp;
|
||||
}
|
||||
col0Changed = col1Changed = colorChanged = true;
|
||||
}
|
||||
|
||||
//set effect parameters
|
||||
@ -727,6 +740,11 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
updateVal(&req, "SX=", &effectSpeed);
|
||||
updateVal(&req, "IX=", &effectIntensity);
|
||||
updateVal(&req, "FP=", &effectPalette, 0, strip.getPaletteCount()-1);
|
||||
strip.setMode(selectedSeg, effectCurrent);
|
||||
selseg.speed = effectSpeed;
|
||||
selseg.intensity = effectIntensity;
|
||||
selseg.palette = effectPalette;
|
||||
if (effectCurrent != prevEffect || effectSpeed != prevSpeed || effectIntensity != prevIntensity || effectPalette != prevPalette) effectChanged = true;
|
||||
|
||||
//set advanced overlay
|
||||
pos = req.indexOf(F("OL="));
|
||||
@ -857,45 +875,21 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
//you can add more if you need
|
||||
|
||||
//apply to all selected manually to prevent #1618. Temporary
|
||||
bool col0Changed = false, col1Changed = false;
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
if (col[i] != prevCol[i]) col0Changed = true;
|
||||
if (colSec[i] != prevColSec[i]) col1Changed = true;
|
||||
}
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++)
|
||||
{
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isSelected()) continue;
|
||||
if (effectCurrent != prevEffect) {
|
||||
strip.setMode(i, effectCurrent);
|
||||
effectChanged = true;
|
||||
}
|
||||
if (effectSpeed != prevSpeed) {
|
||||
seg.speed = effectSpeed;
|
||||
effectChanged = true;
|
||||
}
|
||||
if (effectIntensity != prevIntensity) {
|
||||
seg.intensity = effectIntensity;
|
||||
effectChanged = true;
|
||||
}
|
||||
if (effectPalette != prevPalette) {
|
||||
seg.palette = effectPalette;
|
||||
effectChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (col0Changed) {
|
||||
if (selectedSeg == strip.getMainSegmentId()) {
|
||||
strip.applyToAllSelected = true;
|
||||
strip.setColor(0, colorFromRgbw(col));
|
||||
}
|
||||
}
|
||||
if (col1Changed) {
|
||||
if (selectedSeg == strip.getMainSegmentId()) {
|
||||
strip.applyToAllSelected = true;
|
||||
strip.setColor(1, colorFromRgbw(colSec));
|
||||
if (strip.applyToAllSelected) {
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment& seg = strip.getSegment(i);
|
||||
if (!seg.isActive() || !seg.isSelected() || i == selectedSeg) continue;
|
||||
if (effectCurrent != prevEffect) strip.setMode(i, effectCurrent);
|
||||
if (effectSpeed != prevSpeed) seg.speed = effectSpeed;
|
||||
if (effectIntensity != prevIntensity) seg.intensity = effectIntensity;
|
||||
if (effectPalette != prevPalette) seg.palette = effectPalette;
|
||||
if (col0Changed) seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
|
||||
if (col1Changed) seg.colors[1] = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||
if (col2Changed) seg.colors[2] = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
|
||||
}
|
||||
}
|
||||
strip.applyToAllSelected = false;
|
||||
setValuesFromMainSeg();
|
||||
//end of temporary fix code
|
||||
|
||||
if (!apply) return true; //when called by JSON API, do not call colorUpdated() here
|
||||
@ -904,8 +898,6 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
|
||||
pos = req.indexOf(F("IN"));
|
||||
if (pos < 1) XML_response(request);
|
||||
|
||||
strip.applyToAllSelected = false;
|
||||
|
||||
pos = req.indexOf(F("&NN")); //do not send UDP notifications this time
|
||||
colorUpdated((pos > 0) ? CALL_MODE_NO_NOTIFY : CALL_MODE_DIRECT_CHANGE);
|
||||
|
||||
|
125
wled00/udp.cpp
125
wled00/udp.cpp
@ -4,7 +4,9 @@
|
||||
* UDP sync notifier / Realtime / Hyperion / TPM2.NET
|
||||
*/
|
||||
|
||||
#define WLEDPACKETSIZE (40+(MAX_NUM_SEGMENTS*3))
|
||||
#define UDP_SEG_SIZE 22
|
||||
#define SEG_OFFSET (41+(MAX_NUM_SEGMENTS*UDP_SEG_SIZE))
|
||||
#define WLEDPACKETSIZE (41+(MAX_NUM_SEGMENTS*UDP_SEG_SIZE)+0)
|
||||
#define UDP_IN_MAXSIZE 1472
|
||||
#define PRESUMED_NETWORK_DELAY 3 //how many ms could it take on avg to reach the receiver? This will be added to transmitted times
|
||||
|
||||
@ -86,13 +88,37 @@ void notify(byte callMode, bool followUp)
|
||||
udpOut[38] = mainseg.cct;
|
||||
|
||||
udpOut[39] = strip.getMaxSegments();
|
||||
udpOut[40] = UDP_SEG_SIZE; //size of each loop iteration (one segment)
|
||||
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
|
||||
WS2812FX::Segment &selseg = strip.getSegment(i);
|
||||
udpOut[40+i*3] = selseg.options & 0x0F; //only take into account mirrored, selected, on, reversed
|
||||
udpOut[41+i*3] = selseg.spacing;
|
||||
udpOut[42+i*3] = selseg.grouping;
|
||||
uint16_t ofs = 41 + i*UDP_SEG_SIZE; //start of segment offset byte
|
||||
udpOut[0 +ofs] = selseg.grouping;
|
||||
udpOut[1 +ofs] = selseg.spacing;
|
||||
udpOut[2 +ofs] = selseg.offset >> 8;
|
||||
udpOut[3 +ofs] = selseg.offset & 0xFF;
|
||||
udpOut[4 +ofs] = selseg.options & 0x0F; //only take into account mirrored, selected, on, reversed
|
||||
udpOut[5 +ofs] = selseg.opacity;
|
||||
udpOut[6 +ofs] = selseg.mode;
|
||||
udpOut[7 +ofs] = selseg.speed;
|
||||
udpOut[8 +ofs] = selseg.intensity;
|
||||
udpOut[9 +ofs] = selseg.palette;
|
||||
udpOut[10+ofs] = R(selseg.colors[0]);
|
||||
udpOut[11+ofs] = G(selseg.colors[0]);
|
||||
udpOut[12+ofs] = B(selseg.colors[0]);
|
||||
udpOut[13+ofs] = W(selseg.colors[0]);
|
||||
udpOut[14+ofs] = R(selseg.colors[1]);
|
||||
udpOut[15+ofs] = G(selseg.colors[1]);
|
||||
udpOut[16+ofs] = B(selseg.colors[1]);
|
||||
udpOut[17+ofs] = W(selseg.colors[1]);
|
||||
udpOut[18+ofs] = R(selseg.colors[2]);
|
||||
udpOut[19+ofs] = G(selseg.colors[2]);
|
||||
udpOut[20+ofs] = B(selseg.colors[2]);
|
||||
udpOut[21+ofs] = W(selseg.colors[2]);
|
||||
}
|
||||
|
||||
//uint16_t offs = SEG_OFFSET;
|
||||
//next value to be added has index: udpOut[offs + 0]
|
||||
|
||||
IPAddress broadcastIp;
|
||||
broadcastIp = ~uint32_t(Network.subnetMask()) | uint32_t(Network.gatewayIP());
|
||||
|
||||
@ -256,24 +282,26 @@ void handleNotifications()
|
||||
|
||||
bool someSel = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects);
|
||||
//apply colors from notification
|
||||
if (receiveNotificationColor || !someSel)
|
||||
{
|
||||
col[0] = udpIn[3];
|
||||
col[1] = udpIn[4];
|
||||
col[2] = udpIn[5];
|
||||
if (receiveNotificationColor || !someSel) {
|
||||
if (version < 11 || !receiveSegmentOptions) {
|
||||
// only change col[] if not syncing full segments
|
||||
col[0] = udpIn[3];
|
||||
col[1] = udpIn[4];
|
||||
col[2] = udpIn[5];
|
||||
}
|
||||
if (version > 0) //sending module's white val is intended
|
||||
{
|
||||
col[3] = udpIn[10];
|
||||
if (version > 1)
|
||||
{
|
||||
// only change col[3] if not syncing full segments
|
||||
if (version < 11 || !receiveSegmentOptions) col[3] = udpIn[10];
|
||||
if (version > 1 && (version < 11 || !receiveSegmentOptions)) {
|
||||
// only change colSec[] if not syncing full segments
|
||||
colSec[0] = udpIn[12];
|
||||
colSec[1] = udpIn[13];
|
||||
colSec[2] = udpIn[14];
|
||||
colSec[3] = udpIn[15];
|
||||
}
|
||||
if (version > 6)
|
||||
{
|
||||
strip.setColor(2, udpIn[20], udpIn[21], udpIn[22], udpIn[23]); //tertiary color
|
||||
if (version > 6 && (version < 11 || !receiveSegmentOptions)) {
|
||||
strip.setColor(2, RGBW32(udpIn[20], udpIn[21], udpIn[22], udpIn[23])); //tertiary color
|
||||
}
|
||||
if (version > 9 && version < 200 && udpIn[37] < 255) { //valid CCT/Kelvin value
|
||||
uint8_t cct = udpIn[38];
|
||||
@ -291,24 +319,34 @@ void handleNotifications()
|
||||
if (version < 200 && (receiveNotificationEffects || !someSel))
|
||||
{
|
||||
if (currentPlaylist>=0) unloadPlaylist();
|
||||
if (version>10) {
|
||||
if (receiveSegmentOptions) {
|
||||
// will not sync start & stop
|
||||
uint8_t srcSegs = udpIn[39];
|
||||
if (srcSegs > strip.getMaxSegments()) srcSegs = strip.getMaxSegments();
|
||||
for (uint8_t i = 0; i < srcSegs; i++) {
|
||||
WS2812FX::Segment& selseg = strip.getSegment(i);
|
||||
for (uint8_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[40+i*3] >> j) & 0x01); //only take into account mirrored, selected, on, reversed
|
||||
strip.setSegment(i, selseg.start, selseg.stop, udpIn[42+i*3], udpIn[41+i*3], selseg.offset); // will also properly reset segments
|
||||
}
|
||||
}
|
||||
}
|
||||
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
|
||||
effectSpeed = udpIn[9];
|
||||
if (version > 2) effectIntensity = udpIn[16];
|
||||
if (version > 4 && udpIn[19] < strip.getPaletteCount()) effectPalette = udpIn[19];
|
||||
if (version > 5)
|
||||
{
|
||||
if (version > 10 && receiveSegmentOptions) {
|
||||
//does not sync start & stop
|
||||
uint8_t srcSegs = udpIn[39];
|
||||
if (srcSegs > strip.getMaxSegments()) srcSegs = strip.getMaxSegments();
|
||||
for (uint8_t i = 0; i < srcSegs; i++) {
|
||||
WS2812FX::Segment& selseg = strip.getSegment(i);
|
||||
uint16_t ofs = 41 + i*UDP_SEG_SIZE; //start of segment offset byte
|
||||
for (uint8_t j = 0; j<4; j++) selseg.setOption(j, (udpIn[4 +ofs] >> j) & 0x01); //only take into account mirrored, selected, on, reversed
|
||||
selseg.setOpacity( udpIn[5+ofs], i);
|
||||
strip.setMode(i, udpIn[6+ofs]);
|
||||
selseg.speed = udpIn[7+ofs];
|
||||
selseg.intensity = udpIn[8+ofs];
|
||||
selseg.palette = udpIn[9+ofs];
|
||||
selseg.setColor(0, RGBW32(udpIn[10+ofs],udpIn[11+ofs],udpIn[12+ofs],udpIn[13+ofs]), i);
|
||||
selseg.setColor(1, RGBW32(udpIn[14+ofs],udpIn[15+ofs],udpIn[16+ofs],udpIn[17+ofs]), i);
|
||||
selseg.setColor(2, RGBW32(udpIn[18+ofs],udpIn[19+ofs],udpIn[20+ofs],udpIn[21+ofs]), i);
|
||||
strip.setSegment(i, selseg.start, selseg.stop, udpIn[0+ofs], udpIn[1+ofs], (udpIn[2+ofs]<<8 | udpIn[3+ofs])); //also properly resets segments
|
||||
}
|
||||
setValuesFromMainSeg();
|
||||
effectChanged = true;
|
||||
colorChanged = true;
|
||||
} else { //simple effect sync, applies to all selected
|
||||
if (udpIn[8] < strip.getModeCount()) effectCurrent = udpIn[8];
|
||||
effectSpeed = udpIn[9];
|
||||
if (version > 2) effectIntensity = udpIn[16];
|
||||
if (version > 4 && udpIn[19] < strip.getPaletteCount()) effectPalette = udpIn[19];
|
||||
}
|
||||
if (version > 5) {
|
||||
uint32_t t = (udpIn[25] << 24) | (udpIn[26] << 16) | (udpIn[27] << 8) | (udpIn[28]);
|
||||
t += PRESUMED_NETWORK_DELAY; //adjust trivially for network delay
|
||||
t -= millis();
|
||||
@ -462,17 +500,18 @@ void handleNotifications()
|
||||
// API over UDP
|
||||
udpIn[packetSize] = '\0';
|
||||
|
||||
if (!requestJSONBufferLock(18)) return;
|
||||
if (udpIn[0] >= 'A' && udpIn[0] <= 'Z') { //HTTP API
|
||||
String apireq = "win&";
|
||||
apireq += (char*)udpIn;
|
||||
handleSet(nullptr, apireq);
|
||||
} else if (udpIn[0] == '{') { //JSON API
|
||||
DeserializationError error = deserializeJson(doc, udpIn);
|
||||
JsonObject root = doc.as<JsonObject>();
|
||||
if (!error && !root.isNull()) deserializeState(root);
|
||||
if (requestJSONBufferLock(18)) {
|
||||
if (udpIn[0] >= 'A' && udpIn[0] <= 'Z') { //HTTP API
|
||||
String apireq = "win&";
|
||||
apireq += (char*)udpIn;
|
||||
handleSet(nullptr, apireq);
|
||||
} else if (udpIn[0] == '{') { //JSON API
|
||||
DeserializationError error = deserializeJson(doc, udpIn);
|
||||
JsonObject root = doc.as<JsonObject>();
|
||||
if (!error && !root.isNull()) deserializeState(root);
|
||||
}
|
||||
releaseJSONBufferLock();
|
||||
}
|
||||
releaseJSONBufferLock();
|
||||
}
|
||||
|
||||
|
||||
|
@ -187,7 +187,7 @@ void _setRandomColor(bool _sec, bool fromButton)
|
||||
} else {
|
||||
colorHStoRGB(lastRandomIndex*256,255,col);
|
||||
}
|
||||
if (fromButton) colorUpdated(2);
|
||||
if (fromButton) colorUpdated(CALL_MODE_BUTTON);
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
// version code in format yymmddb (b = daily build)
|
||||
#define VERSION 2201111
|
||||
#define VERSION 2201221
|
||||
|
||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||
//#define WLED_USE_MY_CONFIG
|
||||
@ -16,6 +16,7 @@
|
||||
// ESP8266-01 (blue) got too little storage space to work with WLED. 0.10.2 is the last release supporting this unit.
|
||||
|
||||
// ESP8266-01 (black) has 1MB flash and can thus fit the whole program, although OTA update is not possible. Use 1M(128K SPIFFS).
|
||||
// 2-step OTA may still be possible: https://github.com/Aircoookie/WLED/issues/2040#issuecomment-981111096
|
||||
// Uncomment some of the following lines to disable features:
|
||||
// Alternatively, with platformio pass your chosen flags to your custom build target in platformio_override.ini
|
||||
|
||||
@ -422,9 +423,6 @@ WLED_GLOBAL bool interfacesInited _INIT(false);
|
||||
WLED_GLOBAL bool wasConnected _INIT(false);
|
||||
|
||||
// color
|
||||
WLED_GLOBAL byte colIT[] _INIT_N(({ 0, 0, 0, 0 })); // color that was last sent to LEDs
|
||||
WLED_GLOBAL byte colSecIT[] _INIT_N(({ 0, 0, 0, 0 }));
|
||||
|
||||
WLED_GLOBAL byte lastRandomIndex _INIT(0); // used to save last random color so the new one is not the same
|
||||
|
||||
// transitions
|
||||
@ -475,6 +473,7 @@ WLED_GLOBAL byte effectSpeed _INIT(128);
|
||||
WLED_GLOBAL byte effectIntensity _INIT(128);
|
||||
WLED_GLOBAL byte effectPalette _INIT(0);
|
||||
WLED_GLOBAL bool effectChanged _INIT(false);
|
||||
WLED_GLOBAL bool colorChanged _INIT(false);
|
||||
|
||||
// network
|
||||
WLED_GLOBAL bool udpConnected _INIT(false), udp2Connected _INIT(false), udpRgbConnected _INIT(false);
|
||||
|
Loading…
Reference in New Issue
Block a user