Merge pull request #47 from FabLab-Luenen/development

Development -> BETA
This commit is contained in:
bpohvoodoo
2019-10-20 09:37:26 +02:00
committed by GitHub
22 changed files with 5015 additions and 4210 deletions
+161 -264
View File
@@ -1,4 +1,8 @@
#include "definitions.h" #include "definitions.h"
// ***************************************************************************
// Load library "ticker" for blinking status led, mqtt send and save state
// ***************************************************************************
#include <Ticker.h>
#include "version.h" #include "version.h"
// *************************************************************************** // ***************************************************************************
@@ -10,13 +14,10 @@
#include <DNSServer.h> #include <DNSServer.h>
#include <ESP8266WebServer.h> #include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager #include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
#include <FS.h>
#include <WiFiClient.h> #include <WiFiClient.h>
#include <ESP8266mDNS.h> #include <ESP8266mDNS.h>
#include <FS.h>
#if ENABLE_STATE_SAVE == 0
#include <EEPROM.h>
#endif
#include <WebSockets.h> //https://github.com/Links2004/arduinoWebSockets #include <WebSockets.h> //https://github.com/Links2004/arduinoWebSockets
#include <WebSocketsServer.h> #include <WebSocketsServer.h>
@@ -28,8 +29,6 @@
GY33_MCU tcs; GY33_MCU tcs;
#endif #endif
#include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson
// MQTT // MQTT
#if defined(ENABLE_MQTT) #if defined(ENABLE_MQTT)
#if ENABLE_MQTT == 0 #if ENABLE_MQTT == 0
@@ -50,12 +49,11 @@
AsyncMqttClient * mqtt_client; AsyncMqttClient * mqtt_client;
WiFiEventHandler wifiConnectHandler; WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler; WiFiEventHandler wifiDisconnectHandler;
Ticker mqttReconnectTimer;
Ticker wifiReconnectTimer;
#endif #endif
#endif #if defined(ENABLE_HOMEASSISTANT)
Ticker ha_send_data;
#if defined(ARDUINOJSON_VERSION)
#if !(ARDUINOJSON_VERSION_MAJOR == 6 and ARDUINOJSON_VERSION_MINOR >= 8)
#error "Install ArduinoJson v6.8.x or higher"
#endif #endif
#endif #endif
@@ -169,21 +167,9 @@ WS2812FX * strip = NULL;
} }
#endif #endif
// ***************************************************************************
// Load library "ticker" for blinking status led, mqtt send and save state
// ***************************************************************************
#include <Ticker.h>
Ticker ticker; Ticker ticker;
#if defined(ENABLE_MQTT)
#if ENABLE_MQTT == 1
Ticker mqttReconnectTimer;
Ticker wifiReconnectTimer;
#endif
#if defined(ENABLE_HOMEASSISTANT)
Ticker ha_send_data;
#endif
#endif
void tick() { void tick() {
//toggle state //toggle state
@@ -196,9 +182,6 @@ void tick() {
decode_results results; decode_results results;
#endif #endif
Ticker settings_save_state;
Ticker settings_save_conf;
// *************************************************************************** // ***************************************************************************
// Saved state handling in WifiManager // Saved state handling in WifiManager
// *************************************************************************** // ***************************************************************************
@@ -245,90 +228,22 @@ void saveConfigCallback () {
// *************************************************************************** // ***************************************************************************
#include "spiffs_webserver.h" #include "spiffs_webserver.h"
// ***************************************************************************
// Include: Request handlers
// ***************************************************************************
#include "request_handlers.h"
// *************************************************************************** // ***************************************************************************
// Include: Custom animations // Include: Custom animations
// *************************************************************************** // ***************************************************************************
#include "mode_custom_ws2812fx_animations.h" // Add animations in this file #include "mode_custom_ws2812fx_animations.h" // Add animations in this file
// function to Initialize the strip // ***************************************************************************
void initStrip(uint16_t stripSize = WS2812FXStripSettings.stripSize, char RGBOrder[5] = WS2812FXStripSettings.RGBOrder, uint8_t pin = WS2812FXStripSettings.pin, uint8_t fxoptions = WS2812FXStripSettings.fxoptions ){ // Include: helper functions
DBG_OUTPUT_PORT.println("Initializing strip!"); // ***************************************************************************
/*#if defined(USE_WS2812FX_DMA) #include "helper_functions.h"
if (dma != NULL) {
delete(dma);
}
#endif*/
if (strip != NULL) {
delete(strip);
WS2812FXStripSettings.stripSize = stripSize;
strcpy(WS2812FXStripSettings.RGBOrder, RGBOrder);
WS2812FXStripSettings.pin = pin;
WS2812FXStripSettings.fxoptions = fxoptions;
}
if (ledstates != NULL) { // ***************************************************************************
delete(ledstates); // Include: other functions
} // ***************************************************************************
ledstates = new uint8_t [WS2812FXStripSettings.stripSize]; #include "json_functions.h"
#include "filesystem_functions.h"
#if !defined(LED_TYPE_WS2811) #include "request_handlers.h"
strip = new WS2812FX(stripSize, pin, checkRGBOrder(RGBOrder) + NEO_KHZ800);
#else
strip = new WS2812FX(stripSize, pin, checkRGBOrder(RGBOrder) + NEO_KHZ400);
#endif
// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel. Avoid connecting
// on a live circuit...if you must, connect GND first.
strip->init();
#if defined(USE_WS2812FX_DMA)
initDMA(stripSize);
strip->setCustomShow(DMA_Show);
#endif
//parameters: index, start, stop, mode, color, speed, options
strip->setSegment(selected_segment, 0, stripSize - 1, ws2812fx_mode, hex_colors_trans, convertSpeed(ws2812fx_speed), fxoptions);
strip->setCustomMode(0, F("Autoplay"), myCustomEffect0);
strip->setCustomMode(1, F("Custom WS"), myCustomEffect1);
#if defined(CUSTOM_WS2812FX_ANIMATIONS)
strip->setCustomMode(2, F("TV"), myCustomEffect2);
strip->setCustomMode(3, F("E1.31"), myCustomEffect3);
strip->setCustomMode(4, F("Fire 2012"), myCustomEffect4);
strip->setCustomMode(5, F("Gradient"), myCustomEffect5);
gReverseDirection = (WS2812FXStripSettings.fxoptions & 128);
if (e131 != NULL) { delete(e131); }
e131 = new ESPAsyncE131(END_UNIVERSE - START_UNIVERSE + 1);
float universe_leds = 170.0; // a universe has only 512 (0..511) channels: 3*170 or 4*128 <= 512
if (strstr(WS2812FXStripSettings.RGBOrder, "W") != NULL) {
//universe_leds = 128.0;
}
float float_enduni = stripSize/universe_leds;
uint8_t END_UNIVERSE = stripSize/universe_leds;
if (float_enduni > END_UNIVERSE) {
END_UNIVERSE = END_UNIVERSE +1;
}
// if (e131.begin(E131_UNICAST)) // Listen via Unicast
if (e131->begin(E131_MULTICAST, START_UNIVERSE, END_UNIVERSE)) {// Listen via Multicast
DBG_OUTPUT_PORT.println(F("Listening for data..."));
} else {
DBG_OUTPUT_PORT.println(F("*** e131.begin failed ***"));
}
#endif
}
#if defined(ENABLE_MQTT) #if defined(ENABLE_MQTT)
void initMqtt() { void initMqtt() {
@@ -394,9 +309,6 @@ void setup() {
delay(500); delay(500);
DBG_OUTPUT_PORT.println(""); DBG_OUTPUT_PORT.println("");
DBG_OUTPUT_PORT.println("Starting...Main Setup"); DBG_OUTPUT_PORT.println("Starting...Main Setup");
#if ENABLE_STATE_SAVE == 0
EEPROM.begin(512);
#endif
// set builtin led pin as output // set builtin led pin as output
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
// button pin setup // button pin setup
@@ -415,6 +327,10 @@ void setup() {
} }
#endif #endif
#if defined(POWER_SUPPLY)
pinMode(POWER_SUPPLY, OUTPUT); // output to control external power supply
#endif
// start ticker with 0.5 because we start in AP mode and try to connect // start ticker with 0.5 because we start in AP mode and try to connect
ticker.attach(0.5, tick); ticker.attach(0.5, tick);
@@ -444,37 +360,30 @@ void setup() {
#if defined(ENABLE_STATE_SAVE) #if defined(ENABLE_STATE_SAVE)
//Strip Config //Strip Config
#if ENABLE_STATE_SAVE == 1
(readConfigFS()) ? DBG_OUTPUT_PORT.println("WiFiManager config FS read success!"): DBG_OUTPUT_PORT.println("WiFiManager config FS Read failure!"); (readConfigFS()) ? DBG_OUTPUT_PORT.println("WiFiManager config FS read success!"): DBG_OUTPUT_PORT.println("WiFiManager config FS Read failure!");
delay(250); delay(250);
(readStateFS()) ? DBG_OUTPUT_PORT.println("Strip state config FS read Success!") : DBG_OUTPUT_PORT.println("Strip state config FS read failure!"); (readStateFS()) ? DBG_OUTPUT_PORT.println("Strip state config FS read Success!") : DBG_OUTPUT_PORT.println("Strip state config FS read failure!");
#endif char _stripSize[6], _fx_options[5], _rgbOrder[5]; //needed tempararily for WiFiManager Settings
#if ENABLE_STATE_SAVE == 0
(setConfByConfString(readEEPROM(0, 222)))? DBG_OUTPUT_PORT.println("WiFiManager config EEPROM read success!"): DBG_OUTPUT_PORT.println("WiFiManager config EEPROM Read failure!");
delay(250);
(setModeByStateString(readEEPROM(256, 66)))? DBG_OUTPUT_PORT.println("Strip state config EEPROM read Success!") : DBG_OUTPUT_PORT.println("Strip state config EEPROM read failure!");
#endif
char tmp_strip_size[6], tmp_fxoptions[5], tmp_rgbOrder[5]; //needed tempararily for WiFiManager Settings
WiFiManagerParameter custom_hostname("hostname", "Hostname", HOSTNAME, 64, " maxlength=64"); WiFiManagerParameter custom_hostname("hostname", "Hostname", HOSTNAME, 64, " maxlength=64");
#if defined(ENABLE_MQTT) #if defined(ENABLE_MQTT)
char tmp_mqtt_port[6]; //needed tempararily for WiFiManager Settings char _mqtt_port[6]; //needed tempararily for WiFiManager Settings
WiFiManagerParameter custom_mqtt_host("host", "MQTT hostname", mqtt_host, 64, " maxlength=64"); WiFiManagerParameter custom_mqtt_host("host", "MQTT hostname", mqtt_host, 64, " maxlength=64");
sprintf(tmp_mqtt_port, "%d", mqtt_port); sprintf(_mqtt_port, "%d", mqtt_port);
WiFiManagerParameter custom_mqtt_port("port", "MQTT port", tmp_mqtt_port, 5, " maxlength=5 type=\"number\""); WiFiManagerParameter custom_mqtt_port("port", "MQTT port", _mqtt_port, 5, " maxlength=5 type=\"number\"");
WiFiManagerParameter custom_mqtt_user("user", "MQTT user", mqtt_user, 32, " maxlength=32"); WiFiManagerParameter custom_mqtt_user("user", "MQTT user", mqtt_user, 32, " maxlength=32");
WiFiManagerParameter custom_mqtt_pass("pass", "MQTT pass", mqtt_pass, 32, " maxlength=32 type=\"password\""); WiFiManagerParameter custom_mqtt_pass("pass", "MQTT pass", mqtt_pass, 32, " maxlength=32 type=\"password\"");
#endif #endif
sprintf(tmp_strip_size, "%d", WS2812FXStripSettings.stripSize); sprintf(_stripSize, "%d", Config.stripSize);
WiFiManagerParameter custom_strip_size("strip_size", "Number of LEDs", tmp_strip_size, 4, " maxlength=4 type=\"number\""); WiFiManagerParameter custom_strip_size("strip_size", "Number of LEDs", _stripSize, 4, " maxlength=4 type=\"number\"");
#if !defined(USE_WS2812FX_DMA) #if !defined(USE_WS2812FX_DMA)
char tmp_led_pin[3]; char tmp_led_pin[3];
sprintf(tmp_led_pin, "%d", WS2812FXStripSettings.pin); sprintf(tmp_led_pin, "%d", Config.pin);
WiFiManagerParameter custom_led_pin("led_pin", "LED GPIO", tmp_led_pin, 2, " maxlength=2 type=\"number\""); WiFiManagerParameter custom_led_pin("led_pin", "LED GPIO", tmp_led_pin, 2, " maxlength=2 type=\"number\"");
#endif #endif
sprintf(tmp_rgbOrder, "%s", WS2812FXStripSettings.RGBOrder); sprintf(_rgbOrder, "%s", Config.RGBOrder);
WiFiManagerParameter custom_rgbOrder("rgbOrder", "RGBOrder", tmp_rgbOrder, 4, " maxlength=4"); WiFiManagerParameter custom_rgbOrder("rgbOrder", "RGBOrder", _rgbOrder, 4, " maxlength=4");
sprintf(tmp_fxoptions, "%d", WS2812FXStripSettings.fxoptions); sprintf(_fx_options, "%d", segState.options);
WiFiManagerParameter custom_fxoptions("fxoptions", "fxOptions", tmp_fxoptions, 3, " maxlength=3"); WiFiManagerParameter custom_fxoptions("fxoptions", "fxOptions", _fx_options, 3, " maxlength=3");
#endif #endif
@@ -538,31 +447,16 @@ void setup() {
strcpy(mqtt_user, custom_mqtt_user.getValue()); strcpy(mqtt_user, custom_mqtt_user.getValue());
strcpy(mqtt_pass, custom_mqtt_pass.getValue()); strcpy(mqtt_pass, custom_mqtt_pass.getValue());
#endif #endif
strcpy(tmp_strip_size, custom_strip_size.getValue()); strcpy(_stripSize, custom_strip_size.getValue());
WS2812FXStripSettings.stripSize = constrain(atoi(custom_strip_size.getValue()), 1, MAXLEDS); Config.stripSize = constrain(atoi(custom_strip_size.getValue()), 1, MAXLEDS);
#if !defined(USE_WS2812FX_DMA) #if !defined(USE_WS2812FX_DMA)
checkPin(atoi(custom_led_pin.getValue())); checkPin(atoi(custom_led_pin.getValue()));
#endif #endif
strcpy(tmp_rgbOrder, custom_rgbOrder.getValue()); strcpy(_rgbOrder, custom_rgbOrder.getValue());
checkRGBOrder(tmp_rgbOrder); checkRGBOrder(_rgbOrder);
WS2812FXStripSettings.fxoptions = atoi(custom_fxoptions.getValue()); segState.options = atoi(custom_fxoptions.getValue());
if (updateConfig) { if (updateConfig) {
#if ENABLE_STATE_SAVE == 1
(writeConfigFS(updateConfig)) ? DBG_OUTPUT_PORT.println("WiFiManager config FS Save success!"): DBG_OUTPUT_PORT.println("WiFiManager config FS Save failure!"); (writeConfigFS(updateConfig)) ? DBG_OUTPUT_PORT.println("WiFiManager config FS Save success!"): DBG_OUTPUT_PORT.println("WiFiManager config FS Save failure!");
#endif
#if ENABLE_STATE_SAVE == 0
char last_conf[225];
DBG_OUTPUT_PORT.println("Saving WiFiManager config");
#if defined(ENABLE_MQTT)
snprintf(last_conf, sizeof(last_conf), "CNF|%64s|%64s|%5d|%32s|%32s|%4d|%2d|%4s|%3d|%1d", HOSTNAME, mqtt_host, mqtt_port, mqtt_user, mqtt_pass, WS2812FXStripSettings.stripSize, WS2812FXStripSettings.pin, WS2812FXStripSettings.RGBOrder, WS2812FXStripSettings.fxoptions, transEffect);
#else
snprintf(last_conf, sizeof(last_conf), "CNF|%64s|%64s|%5d|%32s|%32s|%4d|%2d|%4s|%3d|%1d", HOSTNAME, "", "", "", "", WS2812FXStripSettings.stripSize, WS2812FXStripSettings.pin, WS2812FXStripSettings.RGBOrder, WS2812FXStripSettings.fxoptions, transEffect);
#endif
last_conf[sizeof(last_conf)] = 0x00;
writeEEPROM(0, 224, last_conf);
EEPROM.commit();
updateConfig = false;
#endif
} }
#endif #endif
@@ -641,11 +535,11 @@ void setup() {
DBG_OUTPUT_PORT.print("Use http://"); DBG_OUTPUT_PORT.print("Use http://");
DBG_OUTPUT_PORT.print(HOSTNAME); DBG_OUTPUT_PORT.print(HOSTNAME);
DBG_OUTPUT_PORT.println(".local/ when you have Bonjour installed."); DBG_OUTPUT_PORT.println(".local/ when you have Bonjour installed.");
#if !defined(USE_HTML_MIN_GZ)
DBG_OUTPUT_PORT.print("New users: Open http://"); DBG_OUTPUT_PORT.print("New users: Open http://");
DBG_OUTPUT_PORT.print(WiFi.localIP()); DBG_OUTPUT_PORT.print(WiFi.localIP());
DBG_OUTPUT_PORT.println("/upload to upload the webpages first."); DBG_OUTPUT_PORT.println("/upload to upload the webpages first.");
#endif
DBG_OUTPUT_PORT.println(""); DBG_OUTPUT_PORT.println("");
// *************************************************************************** // ***************************************************************************
@@ -671,9 +565,8 @@ void setup() {
#if defined(ENABLE_REMOTE) #if defined(ENABLE_REMOTE)
irrecv.enableIRIn(); // Start the receiver irrecv.enableIRIn(); // Start the receiver
#endif #endif
ws2812fx_speed_actual = ws2812fx_speed; fx_speed = segState.speed[State.segment];
brightness_trans = brightness; brightness_trans = State.brightness;
memcpy(hex_colors, hex_colors_trans, sizeof(hex_colors_trans));
initStrip(); initStrip();
strip->setBrightness(0); strip->setBrightness(0);
DBG_OUTPUT_PORT.println("finished Main Setup!"); DBG_OUTPUT_PORT.println("finished Main Setup!");
@@ -734,94 +627,112 @@ void loop() {
// *************************************************************************** // ***************************************************************************
// Simple statemachine that handles the different modes // Simple statemachine that handles the different modes
// *************************************************************************** // ***************************************************************************
if ((mode == OFF) && ((strip->getBrightness() == 0) || !transEffect)) {
if ((State.mode == OFF) && ((strip->getBrightness() == 0) || !Config.transEffect)) {
if(strip->isRunning()) { if(strip->isRunning()) {
strip->strip_off(); // Workaround: to be shure, strip->strip_off(); // Workaround: to be shure,
delay(10); // that strip is really off. Sometimes strip->stop isn't enought delay(10); // that strip is really off. Sometimes strip->stop isn't enought
strip->stop(); // should clear memory strip->stop(); // should clear memory
autoCount = 0; for (uint8_t i = 0; i < Config.segments; i++) {
autoDelay = 0; autoCount[i] = 0;
autoDelay[i] = 0;
}
} else { } else {
if (prevmode != mode) { // Start temporarily to clear strip if (prevmode != State.mode) { // Start temporarily to clear strip
strip->start(); strip->start();
strip->strip_off(); // Workaround: to be shure, strip->strip_off(); // Workaround: to be shure,
delay(10); // that strip is really off. Sometimes strip->stop isn't enought delay(10); // that strip is really off. Sometimes strip->stop isn't enought
strip->stop(); // should clear memory strip->stop(); // should clear memory
autoCount = 0; for (uint8_t i = 0; i < Config.segments; i++) {
autoDelay = 0; autoCount[i] = 0;
autoDelay[i] = 0;
}
} }
} }
} }
if (mode == OFF) { if (State.mode == OFF) {
if (prevmode != mode) { if (prevmode != State.mode) {
#if defined(ENABLE_MQTT) #if defined(ENABLE_MQTT)
snprintf(mqtt_buf, sizeof(mqtt_buf), "OK =off", ""); snprintf(mqtt_buf, sizeof(mqtt_buf), "OK =off", "");
#endif #endif
if (transEffect) { #if defined(POWER_SUPPLY)
digitalWrite(POWER_SUPPLY, LOW); // power off -> external power supply
#endif
if (Config.transEffect) {
brightness_trans = 0; brightness_trans = 0;
} }
} }
} }
#if defined(POWER_SUPPLY)
if (mode == INIT_STRIP) { if (State.mode != OFF) {
mode = prevmode; if (prevmode != State.mode) {digitalWrite(POWER_SUPPLY, HIGH); } // power on -> external power supply
strip->strip_off();
delay(10);
if(strip->isRunning()) strip->stop();
initStrip();
prevmode = INIT_STRIP;
} }
#endif
if (mode == SET) { if (State.mode == SET) {
mode = HOLD; State.mode = HOLD;
// Mode // Segment
if (ws2812fx_mode != strip->getMode(selected_segment)) { // SET_MODE if (prevsegment != State.segment) {
#if defined(ENABLE_MQTT) #if defined(ENABLE_MQTT)
snprintf(mqtt_buf, sizeof(mqtt_buf), "OK /%i", ws2812fx_mode); snprintf(mqtt_buf, sizeof(mqtt_buf), "OK Ss%i", State.segment);
#endif
//prevsegment = State.segment;
}
// Mode
if (segState.mode[State.segment] != fx_mode) {
segState.mode[State.segment] = fx_mode;
#if defined(ENABLE_MQTT)
snprintf(mqtt_buf, sizeof(mqtt_buf), "OK /%i", segState.mode[State.segment]);
#endif #endif
strip->strip_off(); strip->strip_off();
autoCount = 0; autoCount[State.segment] = 0;
autoDelay = 0; autoDelay[State.segment] = 0;
strip->setMode(selected_segment, ws2812fx_mode); //strip->setSpeed(State.segment, segState.speed[State.segment]);
//strip->setColors(State.segment, segState.colors[State.segment]);
strip->setMode(State.segment, segState.mode[State.segment]);
//strip->trigger;
} }
//Color //Color
/*if (memcmp(hex_colors_trans, strip->getColors(selected_segment), sizeof(hex_colors_trans)) != 0) { /*if (memcmp(segmentState.colors[prevsegment)], strip->getColors(prevsegment), sizeof(segmentState.colors[prevsegment)])) != 0) {
convertColors();
}*/ }*/
// Brightness // Brightness
if (strip->getBrightness() != brightness) { if (strip->getBrightness() != State.brightness) {
#if defined(ENABLE_MQTT) #if defined(ENABLE_MQTT)
snprintf(mqtt_buf, sizeof(mqtt_buf), "OK %%%i", brightness); snprintf(mqtt_buf, sizeof(mqtt_buf), "OK %%%i", State.brightness);
#endif #endif
brightness_trans = brightness; brightness_trans = State.brightness;
} }
// Speed // Speed
if (ws2812fx_speed_actual != ws2812fx_speed) { if (fx_speed != segState.speed[State.segment]) {
#if defined(ENABLE_MQTT) #if defined(ENABLE_MQTT)
snprintf(mqtt_buf, sizeof(mqtt_buf), "OK ?%i", ws2812fx_speed); snprintf(mqtt_buf, sizeof(mqtt_buf), "OK ?%i", segState.speed[prevsegment]);
#endif #endif
} }
prevmode = SET; prevmode = SET;
strip->trigger();
} }
if (prevmode != mode) { if ((State.mode == HOLD) || ((State.mode == OFF) && (strip->getBrightness() > 0) && Config.transEffect)) {
if(!strip->isRunning()) strip->start();
strip->service();
for (uint8_t i = 0; i < Config.segments; i++) {
if (segState.mode[i] == FX_MODE_CUSTOM_0) { handleAutoPlay(i); };
}
}
if (prevmode != State.mode) {
if (segState.mode[prevsegment] != FX_MODE_CUSTOM_0) {
convertColors(); convertColors();
if (memcmp(hex_colors_trans, strip->getColors(selected_segment), sizeof(hex_colors_trans)) != 0) { if (memcmp(hexcolors_trans, strip->getColors(prevsegment), sizeof(hexcolors_trans)) != 0) {
DBG_OUTPUT_PORT.println("Colors not equal!"); DBG_OUTPUT_PORT.println("Color changed!");
convertColorsFade(); trans_cnt_max = convertColorsFade(prevsegment);
trans_cnt = 1; trans_cnt = 1;
memcpy(segState.colors[prevsegment], hexcolors_trans, sizeof(hexcolors_trans));
}
strip->setSpeed(prevsegment, convertSpeed(fx_speed));
} }
strip->setSpeed(selected_segment, convertSpeed(ws2812fx_speed_actual));
//strip->setBrightness(brightness_actual); //strip->setBrightness(brightness_actual);
if (prevmode != INIT_STRIP) { // do not save if INIT_STRIP mode was set
#if defined(ENABLE_STATE_SAVE)
if(!settings_save_state.active()) settings_save_state.once(3, tickerSaveState);
#endif
snprintf(last_state, sizeof(last_state), "STA|%2d|%3d|%3d|%3d|%3d|%3d|%3d|%3d|%3d|%3d|%3d|%3d|%3d|%3d|%3d|%3d", prevmode, ws2812fx_mode, ws2812fx_speed, brightness, main_color.red, main_color.green, main_color.blue, main_color.white, back_color.red, back_color.green, back_color.blue, back_color.white, xtra_color.red, xtra_color.green, xtra_color.blue, xtra_color.white);
last_state[sizeof(last_state) - 1] = 0x00;
}
#if defined(ENABLE_MQTT) #if defined(ENABLE_MQTT)
#if ENABLE_MQTT == 0 #if ENABLE_MQTT == 0
mqtt_client->publish(mqtt_outtopic, mqtt_buf); mqtt_client->publish(mqtt_outtopic, mqtt_buf);
@@ -834,102 +745,75 @@ void loop() {
#endif #endif
#endif #endif
} }
prevmode = State.mode;
#if defined(ENABLE_STATE_SAVE) #if defined(ENABLE_STATE_SAVE)
if (updateState){ if (updateState){
#if ENABLE_STATE_SAVE == 1
(writeStateFS(updateState)) ? DBG_OUTPUT_PORT.println("State FS Save Success!") : DBG_OUTPUT_PORT.println("State FS Save failure!"); (writeStateFS(updateState)) ? DBG_OUTPUT_PORT.println("State FS Save Success!") : DBG_OUTPUT_PORT.println("State FS Save failure!");
#endif }
#if ENABLE_STATE_SAVE == 0 if (updateSegState) {
writeEEPROM(384, 66, last_state); // 384 --> last_state (reserved 66 bytes) (writeSegmentStateFS(updateSegState, prevsegment)) ? DBG_OUTPUT_PORT.println("Segment State FS Save Success!") : DBG_OUTPUT_PORT.println("Segment State FS Save failure!");
EEPROM.commit();
updateState = false;
settings_save_state.detach();
#endif
} }
if (updateConfig) { if (updateConfig) {
#if ENABLE_STATE_SAVE == 1
(writeConfigFS(updateConfig)) ? DBG_OUTPUT_PORT.println("Config FS Save success!"): DBG_OUTPUT_PORT.println("Config FS Save failure!"); (writeConfigFS(updateConfig)) ? DBG_OUTPUT_PORT.println("Config FS Save success!"): DBG_OUTPUT_PORT.println("Config FS Save failure!");
#endif
#if ENABLE_STATE_SAVE == 0
char last_conf[225];
#if defined(ENABLE_MQTT)
snprintf(last_conf, sizeof(last_conf), "CNF|%64s|%64s|%5d|%32s|%32s|%4d|%2d|%4s|%3d|%1d", HOSTNAME, mqtt_host, mqtt_port, mqtt_user, mqtt_pass, WS2812FXStripSettings.stripSize, WS2812FXStripSettings.pin, WS2812FXStripSettings.RGBOrder, WS2812FXStripSettings.fxoptions, transEffect);
#else
snprintf(last_conf, sizeof(last_conf), "CNF|%64s|%64s|%5d|%32s|%32s|%4d|%2d|%4s|%3d|%1d", HOSTNAME, "", "", "", "", WS2812FXStripSettings.stripSize, WS2812FXStripSettings.pin, WS2812FXStripSettings.RGBOrder, WS2812FXStripSettings.fxoptions, transEffect);
#endif
last_conf[sizeof(last_conf) - 1] = 0x00;
writeEEPROM(0, 224, last_conf);
EEPROM.commit();
updateConfig = false;
settings_save_conf.detach();
#endif
} }
#endif #endif
if ((mode == HOLD) || ((mode == OFF) && (strip->getBrightness() > 0) && transEffect)) {
if (ws2812fx_mode == FX_MODE_CUSTOM_0) {
handleAutoPlay();
}
if(!strip->isRunning()) strip->start();
strip->service();
}
// Async color transition // Async color transition
if (memcmp(hex_colors_trans, strip->getColors(selected_segment), sizeof(hex_colors_trans)) != 0) { if ((segState.mode[prevsegment] != FX_MODE_CUSTOM_0) && (memcmp(hexcolors_trans, strip->getColors(prevsegment), sizeof(hexcolors_trans)) != 0)) {
if (transEffect) { if (Config.transEffect) {
if ((trans_cnt > 0) && (trans_cnt < trans_cnt_max)) { if ((trans_cnt > 0) && (trans_cnt < trans_cnt_max)) {
if (colorFadeDelay <= millis()) { if (colorFadeDelay <= millis()) {
uint32_t hex_colors_actual[3] = {}; uint32_t _hexcolors_new[3] = {};
hex_colors_actual[0] = trans(hex_colors_trans[0], hex_colors[0], trans_cnt); _hexcolors_new[0] = trans(hexcolors_trans[0], strip->getColors(prevsegment)[0], trans_cnt, trans_cnt_max);
hex_colors_actual[1] = trans(hex_colors_trans[1], hex_colors[1], trans_cnt); _hexcolors_new[1] = trans(hexcolors_trans[1], strip->getColors(prevsegment)[1], trans_cnt, trans_cnt_max);
hex_colors_actual[2] = trans(hex_colors_trans[2], hex_colors[2], trans_cnt); _hexcolors_new[2] = trans(hexcolors_trans[2], strip->getColors(prevsegment)[2], trans_cnt, trans_cnt_max);
strip->setColors(selected_segment, hex_colors_actual); strip->setColors(prevsegment, _hexcolors_new);
trans_cnt++; trans_cnt++;
colorFadeDelay = millis() + TRANS_COLOR_DELAY; colorFadeDelay = millis() + TRANS_COLOR_DELAY;
if (mode == HOLD) strip->trigger(); if (State.mode == HOLD) strip->trigger();
} }
} else if (trans_cnt >= trans_cnt_max) { } else if (trans_cnt >= trans_cnt_max) {
memcpy(hex_colors, hex_colors_trans, sizeof(hex_colors_trans)); strip->setColors(prevsegment, hexcolors_trans);
strip->setColors(selected_segment, hex_colors); if (State.mode == HOLD) strip->trigger();
if (mode == HOLD) strip->trigger();
trans_cnt = 0;
DBG_OUTPUT_PORT.println("Color transition finished!"); DBG_OUTPUT_PORT.println("Color transition finished!");
trans_cnt = 0;
} }
} else { } else {
memcpy(hex_colors, hex_colors_trans, sizeof(hex_colors_trans)); strip->setColors(prevsegment, hexcolors_trans);
strip->setColors(selected_segment, hex_colors); if (State.mode == HOLD) strip->trigger();
if (mode == HOLD) strip->trigger();
trans_cnt = 0;
} }
} }
// Async speed transition // Async speed transition
if (ws2812fx_speed_actual != ws2812fx_speed) { if ((segState.mode[prevsegment] != FX_MODE_CUSTOM_0) && (fx_speed != segState.speed[prevsegment])) {
if (transEffect) { if (Config.transEffect) {
//if (true == false) { // disabled for the moment
if (speedFadeDelay <= millis()) { if (speedFadeDelay <= millis()) {
DBG_OUTPUT_PORT.println("Speed actual: "); //DBG_OUTPUT_PORT.print("Speed trans actual: ");
DBG_OUTPUT_PORT.println(ws2812fx_speed_actual); if (fx_speed < segState.speed[prevsegment]) {
DBG_OUTPUT_PORT.println(convertSpeed(ws2812fx_speed_actual)); fx_speed++;
DBG_OUTPUT_PORT.println(unconvertSpeed(convertSpeed(ws2812fx_speed_actual)));
if (ws2812fx_speed_actual < ws2812fx_speed) {
ws2812fx_speed_actual++;
} }
if (ws2812fx_speed_actual > ws2812fx_speed) { if (fx_speed > segState.speed[prevsegment]) {
ws2812fx_speed_actual--; fx_speed--;
} }
//DBG_OUTPUT_PORT.println(fx_speed);
speedFadeDelay = millis() + TRANS_DELAY; speedFadeDelay = millis() + TRANS_DELAY;
strip->setSpeed(selected_segment, convertSpeed(ws2812fx_speed_actual)); strip->setSpeed(prevsegment, convertSpeed(fx_speed));
if (mode == HOLD) strip->trigger(); if (State.mode == HOLD) strip->trigger();
} }
} else { } else {
ws2812fx_speed_actual = ws2812fx_speed; fx_speed = segState.speed[prevsegment];
strip->setSpeed(selected_segment, convertSpeed(ws2812fx_speed_actual)); //DBG_OUTPUT_PORT.print("Speed actual: ");
if (mode == HOLD) strip->trigger(); strip->setSpeed(prevsegment, convertSpeed(fx_speed));
//DBG_OUTPUT_PORT.println(fx_speed);
if (State.mode == HOLD) strip->trigger();
} }
} }
// Async brightness transition // Async brightness transition
if (strip->getBrightness() != brightness_trans) { if (strip->getBrightness() != brightness_trans) {
if (transEffect) { if (Config.transEffect) {
if(brightnessFadeDelay <= millis()) { if(brightnessFadeDelay <= millis()) {
if (strip->getBrightness() < brightness_trans) { if (strip->getBrightness() < brightness_trans) {
strip->increaseBrightness(1); strip->increaseBrightness(1);
@@ -938,16 +822,29 @@ void loop() {
strip->decreaseBrightness(1); strip->decreaseBrightness(1);
} }
brightnessFadeDelay = millis() + TRANS_DELAY; brightnessFadeDelay = millis() + TRANS_DELAY;
//if (mode == HOLD) strip->trigger(); if (State.mode == HOLD) strip->trigger();
strip->trigger();
} }
} else { } else {
strip->setBrightness(brightness); brightness_trans = State.brightness;
if (mode == HOLD) strip->trigger(); strip->setBrightness(brightness_trans);
}
}
// Segment change only if color and speed transitions are finished, because they are segment specific
if (prevsegment != State.segment) {
DBG_OUTPUT_PORT.println("Segment not equal");
if ((segState.mode[State.segment] == FX_MODE_CUSTOM_0) || (segState.mode[State.segment] == FX_MODE_CUSTOM_2) || (segState.mode[prevsegment] == FX_MODE_CUSTOM_0)) {
fx_speed = segState.speed[State.segment];
DBG_OUTPUT_PORT.printf("Switched segment from: %i to %i", prevsegment, State.segment);
prevsegment = State.segment;
} else if ((memcmp(hexcolors_trans, strip->getColors(prevsegment), sizeof(hexcolors_trans)) == 0) && (fx_speed == segState.speed[prevsegment])) {
memcpy(hexcolors_trans, segState.colors[State.segment], sizeof(hexcolors_trans));
fx_speed = segState.speed[State.segment];
DBG_OUTPUT_PORT.printf("Switched segment from: %i to %i\r\n", prevsegment, State.segment);
prevsegment = State.segment;
} }
} }
prevmode = mode;
#if defined(ENABLE_REMOTE) #if defined(ENABLE_REMOTE)
handleRemote(); handleRemote();
+4
View File
@@ -340,6 +340,10 @@ uint32_t* WS2812FX::getColors(uint8_t seg) {
return _segments[seg].colors; return _segments[seg].colors;
} }
uint8_t WS2812FX::getSegmentIndex(void) {
return _segment_index;
}
WS2812FX::Segment* WS2812FX::getSegment(void) { WS2812FX::Segment* WS2812FX::getSegment(void) {
return &_segments[_segment_index]; return &_segments[_segment_index];
} }
+2 -1
View File
@@ -500,7 +500,8 @@ class WS2812FX : public Adafruit_NeoPixel {
getNumSegments(void), getNumSegments(void),
get_random_wheel_index(uint8_t), get_random_wheel_index(uint8_t),
getOptions(uint8_t), getOptions(uint8_t),
getNumBytesPerPixel(void); getNumBytesPerPixel(void),
getSegmentIndex(void);
uint16_t uint16_t
random16(void), random16(void),
+3 -1
View File
@@ -182,7 +182,9 @@
var mkfile = document.createElement("button"); var mkfile = document.createElement("button");
mkfile.innerHTML = 'MkFile'; mkfile.innerHTML = 'MkFile';
document.getElementById(element).appendChild(mkfile); document.getElementById(element).appendChild(mkfile);
var para = document.createElement("text");
para.innerHTML = " Press Ctrl-S for save, Ctrl-Z for undo, Ctrl-Shift-Z for redo";
document.getElementById(element).appendChild(para);
function httpPostProcessRequest(){ function httpPostProcessRequest(){
if (xmlHttp.readyState == 4){ if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText); if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
Binary file not shown.
+286 -161
View File
@@ -877,7 +877,7 @@ input[type=number], label{
</div> </div>
</div> </div>
</div> </div>
<div class="flex xs12 sm7"> <div class="flex xs12 sm8">
<div class="sliders container"> <div class="sliders container">
<div class="color-wrap" style="display:none"> <div class="color-wrap" style="display:none">
<div id="color-display"></div> <div id="color-display"></div>
@@ -912,6 +912,13 @@ input[type=number], label{
<input type="number" id="speedNum"> <input type="number" id="speedNum">
<input value="255" type="range" min="0" max="255" id="speed"> <input value="255" type="range" min="0" max="255" id="speed">
</div> </div>
<div id="segments" class="container" style="text-align: left;">
<div class="layout row wrap">
<div class="flex xs12 sm2" id="selectSegLbl" style="text-align: left;"><p>selectSeg</p>
<select id="selectseg" class="custom-select" style="border: 2px solid #aaaaaa; border-radius: 6px; width:90%; "></select>
</div>
</div>
</div>
<div id="message" class="container hidden" style="text-align: left;"> <div id="message" class="container hidden" style="text-align: left;">
<div id="wsmessageLbl" style="text-align: left;"><p>wsMessage</p> <div id="wsmessageLbl" style="text-align: left;"><p>wsMessage</p>
<input type="text" id="wsmessage" style="border: 2px solid #aaaaaa; border-radius: 6px; width:100%;" /> <input type="text" id="wsmessage" style="border: 2px solid #aaaaaa; border-radius: 6px; width:100%;" />
@@ -959,14 +966,25 @@ input[type=number], label{
</div> </div>
</div> </div>
<div class="layout row wrap"> <div class="layout row wrap">
<div class="flex xs12 sm4"><p>selectCount</p> <div class="flex xs12 sm3"><p>selectSegCnt</p>
<input type="number" min="0" max="65535" id="selectcount" style="border: 2px solid #aaaaaa; border-radius: 6px; width:100%;" /> <input type="number" min="1" max="9" id="selectsegcnt" style="border: 2px solid #aaaaaa; border-radius: 6px; width:50%;" />
</div> </div>
<div class="flex xs12 sm4"><p>selectRGBO</p> <div class="flex xs12 sm3"><p>selectCount</p>
<input type="number" min="0" max="65535" id="selectcount" style="border: 2px solid #aaaaaa; border-radius: 6px; width:50%;" />
</div>
<div class="flex xs12 sm3"><p>selectRGBO</p>
<select id="selectrgbo" class="custom-select"></select> <select id="selectrgbo" class="custom-select"></select>
</div> </div>
<div class="flex xs12 sm4"><p>selectPin</p> <div class="flex xs12 sm3"><p>selectPin</p>
<input type="number" min="0" max="16" id="selectpin" style="border: 2px solid #aaaaaa; border-radius: 6px; width:100%;" /> <input type="number" min="0" max="16" id="selectpin" style="border: 2px solid #aaaaaa; border-radius: 6px; width:50%;" />
</div>
</div>
<div class="layout row wrap">
<div class="flex xs12 sm6"><p>segStart</p>
<input type="number" min="0" max="*jsvariable" id="segstart" style="border: 2px solid #aaaaaa; border-radius: 6px; width:90%;" />
</div>
<div class="flex xs12 sm6"><p>segStop</p>
<input type="number" min="0" max="*jsvariable" id="segstop" style="border: 2px solid #aaaaaa; border-radius: 6px; width:90%;" />
</div> </div>
</div> </div>
<div class="layout row wrap"> <div class="layout row wrap">
@@ -1030,6 +1048,7 @@ var language = {
connectError2: " times. Please use the RECONNECT button to try again.", connectError2: " times. Please use the RECONNECT button to try again.",
loadModes: "Loading modes ...", // This language-string is not translated (settings not loaded yet) loadModes: "Loading modes ...", // This language-string is not translated (settings not loaded yet)
loadSettings: "Loading settings ...", // This language-string is not translated (settings not loaded yet) loadSettings: "Loading settings ...", // This language-string is not translated (settings not loaded yet)
loadConfig: "Loading configuration ...",
loadWebsock: "Connecting websockets ...", loadWebsock: "Connecting websockets ...",
loadReady: "Ready ...", loadReady: "Ready ...",
loadError: "Error loading animation modes, please try again...", // This language-string is not translated (settings not loaded yet) loadError: "Error loading animation modes, please try again...", // This language-string is not translated (settings not loaded yet)
@@ -1043,6 +1062,9 @@ var language = {
white: "White", white: "White",
not_greater: "cannot enter numbers greater than 255", not_greater: "cannot enter numbers greater than 255",
not_less: "cannot enter numbers less than 0", not_less: "cannot enter numbers less than 0",
selectSeg: "Select segment",
segStart: "First LED of selected segment",
segStop: "Last LED of selected segment",
wsMessage: "Websocket Message:", wsMessage: "Websocket Message:",
selectLanguage: "Select Language:", selectLanguage: "Select Language:",
selectHostname: "Hostname:", selectHostname: "Hostname:",
@@ -1050,6 +1072,7 @@ var language = {
selectMQTTPort: "and Port:", selectMQTTPort: "and Port:",
selectMQTTUser: "MQTT Username:", selectMQTTUser: "MQTT Username:",
selectMQTTPass: "MQTT Password:", selectMQTTPass: "MQTT Password:",
selectSegCnt: "Number of Segments:",
selectCount: "Strip LED Count:", selectCount: "Strip LED Count:",
selectRGBO: "RGB Order:", selectRGBO: "RGB Order:",
selectPin: "Strip GPIO Pin:", selectPin: "Strip GPIO Pin:",
@@ -1086,6 +1109,7 @@ var language = {
connectError2: " keer geprobeerd. Gebruik de Verbind opnieuw knop om opnieuw te proberen.", connectError2: " keer geprobeerd. Gebruik de Verbind opnieuw knop om opnieuw te proberen.",
loadModes: "Modes laden...", // This language-string is not translated (settings not loaded yet) loadModes: "Modes laden...", // This language-string is not translated (settings not loaded yet)
loadSettings: "Instellingen laden...", // This language-string is not translated (settings not loaded yet) loadSettings: "Instellingen laden...", // This language-string is not translated (settings not loaded yet)
loadConfig: "Configuratie laden ...",
loadWebsock: "Websockets verbinden...", loadWebsock: "Websockets verbinden...",
loadReady: "Klaar...", loadReady: "Klaar...",
loadError: "Fout bij laden van animatie modes, probeer opnieuw...", // This language-string is not translated (settings not loaded yet) loadError: "Fout bij laden van animatie modes, probeer opnieuw...", // This language-string is not translated (settings not loaded yet)
@@ -1099,6 +1123,9 @@ var language = {
white: "Wit", white: "Wit",
not_greater: "Geen nummers hoger dan 255", not_greater: "Geen nummers hoger dan 255",
not_less: "Geen nummers lager dan 0", not_less: "Geen nummers lager dan 0",
selectSeg: "Selecteer segment",
segStart: "Eerste LED van huidige segmenten",
segStop: "Laatste LED van huidige segmenten",
wsMessage: "Websocket message:", wsMessage: "Websocket message:",
selectLanguage: "Selecteer Taal:", selectLanguage: "Selecteer Taal:",
selectHostname: "Hostname:", selectHostname: "Hostname:",
@@ -1106,6 +1133,7 @@ var language = {
selectMQTTPort: "en Port:", selectMQTTPort: "en Port:",
selectMQTTUser: "MQTT gebruikersnaam:", selectMQTTUser: "MQTT gebruikersnaam:",
selectMQTTPass: "MQTT wachtwoord:", selectMQTTPass: "MQTT wachtwoord:",
selectSegCnt: "Number of Segments:",
selectCount: "LED nummer:", selectCount: "LED nummer:",
selectPin: "Strip GPIO Pin:", selectPin: "Strip GPIO Pin:",
selectRGBO: "RGB Order:", selectRGBO: "RGB Order:",
@@ -1142,6 +1170,7 @@ var language = {
connectError2: " mal versucht. Benutze WIEDER VERBINDEN, um es nochmal zu probieren.", connectError2: " mal versucht. Benutze WIEDER VERBINDEN, um es nochmal zu probieren.",
loadModes: "Lade Modi ...", // This language-string is not translated (settings not loaded yet) loadModes: "Lade Modi ...", // This language-string is not translated (settings not loaded yet)
loadSettings: "Lade Einstellungen ...", // This language-string is not translated (settings not loaded yet) loadSettings: "Lade Einstellungen ...", // This language-string is not translated (settings not loaded yet)
loadConfig: "Lade Konfiguration ...",
loadWebsock: "Verbinde Websockets ...", loadWebsock: "Verbinde Websockets ...",
loadReady: "Fertig ...", loadReady: "Fertig ...",
loadError: "Fehler beim Laden der Animations-Modi, bitte nochmal versuchen...", // This language-string is not translated (settings not loaded yet) loadError: "Fehler beim Laden der Animations-Modi, bitte nochmal versuchen...", // This language-string is not translated (settings not loaded yet)
@@ -1155,6 +1184,9 @@ var language = {
white: "Weiß", white: "Weiß",
not_greater: "Akzeptiere keine Nummern größer 255", not_greater: "Akzeptiere keine Nummern größer 255",
not_less: "Akzeptiere keine Nummern kleiner 0", not_less: "Akzeptiere keine Nummern kleiner 0",
selectSeg: "Segment wählen",
segStart: "Erste LED des gewählten Segments",
segStop: "Letzte LED des gewählten Segments",
wsMessage: "Websocket Message:", wsMessage: "Websocket Message:",
selectLanguage: "Sprache auswählen:", selectLanguage: "Sprache auswählen:",
selectHostname: "Hostname:", selectHostname: "Hostname:",
@@ -1162,6 +1194,7 @@ var language = {
selectMQTTPort: "und Port:", selectMQTTPort: "und Port:",
selectMQTTUser: "MQTT Username:", selectMQTTUser: "MQTT Username:",
selectMQTTPass: "MQTT Password:", selectMQTTPass: "MQTT Password:",
selectSegCnt: "Anzahl Segmente:",
selectCount: "Strip LED Anzahl:", selectCount: "Strip LED Anzahl:",
selectRGBO: "RGB Reihenfolge:", selectRGBO: "RGB Reihenfolge:",
selectPin: "Strip GPIO Pin:", selectPin: "Strip GPIO Pin:",
@@ -1281,19 +1314,31 @@ var config = {
mqtt_port: 0, mqtt_port: 0,
mqtt_user: "", mqtt_user: "",
mqtt_pass: "", mqtt_pass: "",
ws_seg: 1,
ws_cnt: 0, ws_cnt: 0,
ws_rgbo: "", ws_rgbo: "",
ws_pin: 0, ws_pin: 0,
ws_fxopt: 0, ws_trans: false,
enable_rgbw: false, enable_rgbw: false
transitionEffects: true
}; };
var data = { var state = {
mode: 0, mode: 0,
segment: 0,
brightness: 0
}
var segstate = {
start: 0,
stop: 0,
mode: null,
speed: 0,
color: {w:0, r:0, g:0, b:0, hex:"00000000", w2:0, r2:0, g2:0, b2:0, hex2:"00000000", w3:0, r3:0, g3:0, b3:0, hex3:"00000000"}, color: {w:0, r:0, g:0, b:0, hex:"00000000", w2:0, r2:0, g2:0, b2:0, hex2:"00000000", w3:0, r3:0, g3:0, b3:0, hex3:"00000000"},
brightness: 192, ws_fxopt: 0
speed: 192, }
ws2812fx_mode: null,
var data = {
init: true,
color_num: 1, color_num: 1,
modes: [], modes: [],
connection: null, connection: null,
@@ -1301,7 +1346,6 @@ var data = {
num_additional_connections: 0, num_additional_connections: 0,
is_connected: false, is_connected: false,
refresh_interval: 0, refresh_interval: 0,
init: true,
color_disabled: false color_disabled: false
}; };
var sendIt; // Timer to prevent lots of sending var sendIt; // Timer to prevent lots of sending
@@ -1331,17 +1375,17 @@ function displayColors(all = false) {
clearTimeout(sendIt); clearTimeout(sendIt);
sendIt = setTimeout(function() { set_color(); }, 50); sendIt = setTimeout(function() { set_color(); }, 50);
} else { } else {
document.getElementById("colorSel1").style.backgroundColor = `rgb(${data.color.r}, ${data.color.g}, ${data.color.b})`; document.getElementById("colorSel1").style.backgroundColor = `rgb(${segstate.color.r}, ${segstate.color.g}, ${segstate.color.b})`;
document.getElementById("colorHex1").innerHTML = "#" + data.color.hex; document.getElementById("colorHex1").innerHTML = "#" + segstate.color.hex;
document.getElementById("colorSel2").style.backgroundColor = `rgb(${data.color.r2}, ${data.color.g2}, ${data.color.b2})`; document.getElementById("colorSel2").style.backgroundColor = `rgb(${segstate.color.r2}, ${segstate.color.g2}, ${segstate.color.b2})`;
document.getElementById("colorHex2").innerHTML = "#" + data.color.hex2; document.getElementById("colorHex2").innerHTML = "#" + segstate.color.hex2;
document.getElementById("colorSel3").style.backgroundColor = `rgb(${data.color.r3}, ${data.color.g3}, ${data.color.b3})`; document.getElementById("colorSel3").style.backgroundColor = `rgb(${segstate.color.r3}, ${segstate.color.g3}, ${segstate.color.b3})`;
document.getElementById("colorHex3").innerHTML = "#" + data.color.hex3; document.getElementById("colorHex3").innerHTML = "#" + segstate.color.hex3;
} }
} }
// initial color val numbers when DOM is loaded // initial color val numbers when DOM is loaded
function colorNumrVals(){ function colorNumVals(){
redNumVal.value = red.value; redNumVal.value = red.value;
greenNumVal.value = green.value; greenNumVal.value = green.value;
blueNumVal.value = blue.value; blueNumVal.value = blue.value;
@@ -1377,44 +1421,44 @@ function initSliderColors(){
function changeRangeNumVal(){ function changeRangeNumVal(){
redNumVal.addEventListener('change', ()=>{ redNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255 // make sure numbers are entered between 0 to 255
red.value = checkNumVal(redNumVal, red.value); red.value = checkNumVal8(redNumVal, red.value);
if (data.color_num === 1) data.color.r = red.value; if (data.color_num === 1) segstate.color.r = red.value;
if (data.color_num === 2) data.color.r2 = red.value; if (data.color_num === 2) segstate.color.r2 = red.value;
if (data.color_num === 3) data.color.r3 = red.value; if (data.color_num === 3) segstate.color.r3 = red.value;
initSliderColors(); initSliderColors();
displayColors(); displayColors();
}); });
greenNumVal.addEventListener('change', ()=>{ greenNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255 // make sure numbers are entered between 0 to 255
green.value = checkNumVal(greenNumVal, green.value); green.value = checkNumVal8(greenNumVal, green.value);
if (data.color_num === 1) data.color.g = green.value; if (data.color_num === 1) segstate.color.g = green.value;
if (data.color_num === 2) data.color.g2 = green.value; if (data.color_num === 2) segstate.color.g2 = green.value;
if (data.color_num === 3) data.color.g3 = green.value; if (data.color_num === 3) segstate.color.g3 = green.value;
initSliderColors(); initSliderColors();
displayColors(); displayColors();
}); });
blueNumVal.addEventListener('change', ()=>{ blueNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255 // make sure numbers are entered between 0 to 255
blue.value = checkNumVal(blueNumVal, blue.value); blue.value = checkNumVal8(blueNumVal, blue.value);
if (data.color_num === 1) data.color.b = blue.value; if (data.color_num === 1) segstate.color.b = blue.value;
if (data.color_num === 2) data.color.b2 = blue.value; if (data.color_num === 2) segstate.color.b2 = blue.value;
if (data.color_num === 3) data.color.b3 = blue.value; if (data.color_num === 3) segstate.color.b3 = blue.value;
initSliderColors(); initSliderColors();
displayColors(); displayColors();
}); });
whiteNumVal.addEventListener('change', ()=>{ whiteNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255 // make sure numbers are entered between 0 to 255
white.value = checkNumVal(whiteNumVal, white.value); white.value = checkNumVal8(whiteNumVal, white.value);
if (data.color_num === 1) data.color.w = white.value; if (data.color_num === 1) segstate.color.w = white.value;
if (data.color_num === 2) data.color.w2 = white.value; if (data.color_num === 2) segstate.color.w2 = white.value;
if (data.color_num === 3) data.color.w3 = white.value; if (data.color_num === 3) segstate.color.w3 = white.value;
initSliderColors(); initSliderColors();
displayColors(); displayColors();
}); });
brightNumVal.addEventListener('change', ()=>{ brightNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255 // make sure numbers are entered between 0 to 255
bright.value = checkNumVal(brightNumVal, bright.value); bright.value = checkNumVal8(brightNumVal, bright.value);
data.brightness = bright.value; state.brightness = bright.value;
initSliderColors(); initSliderColors();
// Send Brightness // Send Brightness
clearTimeout(sendIt); clearTimeout(sendIt);
@@ -1422,14 +1466,14 @@ function changeRangeNumVal(){
}); });
speedNumVal.addEventListener('change', ()=>{ speedNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255 // make sure numbers are entered between 0 to 255
speed.value = checkNumVal(speedNumVal, speed.value); speed.value = checkNumVal8(speedNumVal, speed.value);
data.speed = speed.value; segstate.speed = speed.value;
// Send Speed // Send Speed
clearTimeout(sendIt); clearTimeout(sendIt);
sendIt = setTimeout(function() { set_speed(); }, 50); sendIt = setTimeout(function() { set_speed(); }, 50);
}); });
} }
function checkNumVal(numVal, curVal) { function checkNumVal8(numVal, curVal) {
if(numVal.value > 255) { if(numVal.value > 255) {
alert(language[settings.lang]["not_greater"]); alert(language[settings.lang]["not_greater"]);
numVal.value = curVal; numVal.value = curVal;
@@ -1440,6 +1484,17 @@ function checkNumVal(numVal, curVal) {
return numVal.value; return numVal.value;
} }
function checkNumVal16(numVal, curVal) {
if(numVal.value > 65535) {
alert(language[settings.lang]["not_greater"]);
numVal.value = curVal;
} else if(numVal.value < 0) {
alert(language[settings.lang]["not_less"]);
numVal.value = curVal;
}
return numVal.value;
}
// Color Sliders controls // Color Sliders controls
function initcolorSliders(){ function initcolorSliders(){
var event = new Event('change'); var event = new Event('change');
@@ -1447,7 +1502,7 @@ function initcolorSliders(){
displayColors(); displayColors();
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
// Trigger onChange event to send value // Trigger onChange event to send value
redNumVal.dispatchEvent(event); redNumVal.dispatchEvent(event);
}); });
@@ -1456,7 +1511,7 @@ function initcolorSliders(){
displayColors(); displayColors();
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
// Trigger onChange event to send value // Trigger onChange event to send value
greenNumVal.dispatchEvent(event); greenNumVal.dispatchEvent(event);
}); });
@@ -1465,7 +1520,7 @@ function initcolorSliders(){
displayColors(); displayColors();
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
// Trigger onChange event to send value // Trigger onChange event to send value
blueNumVal.dispatchEvent(event); blueNumVal.dispatchEvent(event);
}); });
@@ -1474,7 +1529,7 @@ function initcolorSliders(){
displayColors(); displayColors();
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
// Trigger onChange event to send value // Trigger onChange event to send value
whiteNumVal.dispatchEvent(event); whiteNumVal.dispatchEvent(event);
}); });
@@ -1482,14 +1537,14 @@ function initcolorSliders(){
bright.addEventListener('input', () => { bright.addEventListener('input', () => {
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
// Trigger onChange event to send value // Trigger onChange event to send value
brightNumVal.dispatchEvent(event); brightNumVal.dispatchEvent(event);
}); });
speed.addEventListener('input', () => { speed.addEventListener('input', () => {
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
// Trigger onChange event to send value // Trigger onChange event to send value
speedNumVal.dispatchEvent(event); speedNumVal.dispatchEvent(event);
}); });
@@ -1518,8 +1573,11 @@ function xhttp(url, post, callback) {
xhr.send(post); xhr.send(post);
} }
function getModes() { function getModes() {
document.getElementById("percentage").innerHTML = "0%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "0,100");
document.getElementById("modal-content").innerHTML = language.en.loadModes;
xhttp("http://" + host + "/get_modes", false, function(e) { xhttp("http://" + host + "/get_modes", false, function(e) {
//console.log("Getting modes list via REST:", e); console.log("Getting modes list via REST:", e);
if (e && e.substring(0,6) !== "ERROR!") { if (e && e.substring(0,6) !== "ERROR!") {
modes = JSON.parse(e); modes = JSON.parse(e);
if (typeof modes[0] !== "undefined") { if (typeof modes[0] !== "undefined") {
@@ -1538,6 +1596,9 @@ function getModes() {
} }
function getConfig() { function getConfig() {
document.getElementById("percentage").innerHTML = "75%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "75,100");
document.getElementById("modal-content").innerHTML = language.en.loadConfig;
xhttp("http://" + host + "/config", false, function(e) { xhttp("http://" + host + "/config", false, function(e) {
console.log("Getting config via REST:", e); console.log("Getting config via REST:", e);
if (e && e.substring(0,6) !== "ERROR!") { if (e && e.substring(0,6) !== "ERROR!") {
@@ -1548,14 +1609,14 @@ function getConfig() {
if (typeof res.mqtt_port !== "undefined") config.mqtt_port = res.mqtt_port; if (typeof res.mqtt_port !== "undefined") config.mqtt_port = res.mqtt_port;
if (typeof res.mqtt_user !== "undefined") config.mqtt_user = res.mqtt_user; if (typeof res.mqtt_user !== "undefined") config.mqtt_user = res.mqtt_user;
if (typeof res.mqtt_pass !== "undefined") config.mqtt_pass = res.mqtt_pass; if (typeof res.mqtt_pass !== "undefined") config.mqtt_pass = res.mqtt_pass;
if (typeof res.ws_seg !== "undefined") config.ws_seg = res.ws_seg;
if (typeof res.ws_cnt !== "undefined") config.ws_cnt = res.ws_cnt; if (typeof res.ws_cnt !== "undefined") config.ws_cnt = res.ws_cnt;
if (typeof res.ws_rgbo !== "undefined") { if (typeof res.ws_rgbo !== "undefined") {
config.ws_rgbo = res.ws_rgbo; config.ws_rgbo = res.ws_rgbo;
config.enable_rgbw = config.ws_rgbo.includes("W"); config.enable_rgbw = config.ws_rgbo.includes("W");
} }
if (typeof res.ws_pin !== "undefined") config.ws_pin = res.ws_pin; if (typeof res.ws_pin !== "undefined") config.ws_pin = res.ws_pin;
if (typeof res.ws_fxopt !== "undefined") config.ws_fxopt = res.ws_fxopt; if (typeof res.ws_trans !== "undefined") config.ws_trans = res.ws_trans;
if (typeof res.transEffect !== "undefined") config.transitionEffects = res.transEffect;
} }
} else { } else {
console.error(e); console.error(e);
@@ -1567,9 +1628,9 @@ function getConfig() {
} else { } else {
document.getElementById("white").parentNode.className = "hidden"; document.getElementById("white").parentNode.className = "hidden";
white.value = 0; white.value = 0;
data.color.w = 0; segstate.color.w = 0;
data.color.w2 = 0; segstate.color.w2 = 0;
data.color.w3 = 0; segstate.color.w3 = 0;
} }
}); });
} }
@@ -1600,11 +1661,11 @@ function showModes(mode, index) {
document.getElementById("modes").appendChild(div); document.getElementById("modes").appendChild(div);
} }
function readSettings() { function readSettings() {
document.getElementById("percentage").innerHTML = "33%"; document.getElementById("percentage").innerHTML = "25%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "33,100"); document.getElementById("percentage-done").setAttribute("stroke-dasharray", "25,100");
document.getElementById("modal-content").innerHTML = language.en.loadSettings; document.getElementById("modal-content").innerHTML = language.en.loadSettings;
xhttp("http://" + host + "/uistate.json", false, function(e) { xhttp("http://" + host + "/uistate.json", false, function(e) {
//console.log("readSettings()", e); console.log("Read Settings: ", e);
tmpsettings = (e && e.substring(0,6) !== "ERROR!") ? JSON.parse(e) : {}; tmpsettings = (e && e.substring(0,6) !== "ERROR!") ? JSON.parse(e) : {};
// Replace default settings with saved ones // Replace default settings with saved ones
for (var set in settings) { for (var set in settings) {
@@ -1612,8 +1673,12 @@ function readSettings() {
if (typeof(tmpsettings[set]) !== "undefined") settings[set] = tmpsettings[set]; if (typeof(tmpsettings[set]) !== "undefined") settings[set] = tmpsettings[set];
} }
applySettings(); applySettings();
if (e && e.substring(0,6) !== "ERROR!") connectAdditionalNodes(); if (e && e.substring(0,6) !== "ERROR!") {
else console.warn("ERROR loading settings", e); connectAdditionalNodes();
} else {
console.warn("ERROR loading settings", e);
saveSettings();
}
}); });
} }
function applySettings() { function applySettings() {
@@ -1678,13 +1743,13 @@ function onSelectColNum(colnum) {
x = document.getElementById("colorSel" + colnum); x = document.getElementById("colorSel" + colnum);
x.className = x.className.replace(/\belevation-3\b/g, "elevation-9"); x.className = x.className.replace(/\belevation-3\b/g, "elevation-9");
// Set ColorPicker and Sliders to selected color // Set ColorPicker and Sliders to selected color
red.value = data.color["r" + (colnum > 1 ? colnum : "")]; red.value = segstate.color["r" + (colnum > 1 ? colnum : "")];
green.value = data.color["g" + (colnum > 1 ? colnum : "")]; green.value = segstate.color["g" + (colnum > 1 ? colnum : "")];
blue.value = data.color["b" + (colnum > 1 ? colnum : "")]; blue.value = segstate.color["b" + (colnum > 1 ? colnum : "")];
white.value = data.color["w" + (colnum > 1 ? colnum : "")]; white.value = segstate.color["w" + (colnum > 1 ? colnum : "")];
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
} }
function initSettings() { function initSettings() {
// Add languages to language select // Add languages to language select
@@ -1736,11 +1801,33 @@ function initSettings() {
config.mqtt_pass = mqtt_pass.value; config.mqtt_pass = mqtt_pass.value;
ws_send("Cmw" + config.mqtt_pass); ws_send("Cmw" + config.mqtt_pass);
}); });
var count = document.getElementById("selectcount"); var selsegment = document.getElementById("selectseg");
count.value = config.ws_cnt; for(var i = 0; i < config.ws_seg; i++) {
count.addEventListener('change', ()=>{ var option = document.createElement("OPTION");
config.ws_cnt = count.value; option.setAttribute("value", i);
ws_send("Csc" + config.ws_cnt); option.innerHTML = i;
selsegment.appendChild(option);
}
selsegment.value = state.segment;
selsegment.addEventListener('change', ()=>{
state.segment = selsegment.value;
ws_send("Ss" + state.segment);
});
var num_segments = document.getElementById("selectsegcnt");
num_segments.value = config.ws_seg;
num_segments.addEventListener('change', ()=>{
config.ws_seg = num_segments.value;
ws_send("Css" + config.ws_seg);
while (selsegment.firstChild) {
selsegment.removeChild(selsegment.firstChild);
}
for(var i = 0; i < config.ws_seg; i++) {
var option = document.createElement("OPTION");
option.setAttribute("value", i);
option.innerHTML = i;
selsegment.appendChild(option);
}
selsegment.value = state.segment;
}); });
var pin = document.getElementById("selectpin"); var pin = document.getElementById("selectpin");
pin.value = config.ws_pin; pin.value = config.ws_pin;
@@ -1760,6 +1847,28 @@ function initSettings() {
config.ws_rgbo = rgbo.value; config.ws_rgbo = rgbo.value;
ws_send("Csr" + config.ws_rgbo); ws_send("Csr" + config.ws_rgbo);
}); });
var start = document.getElementById("segstart");
start.setAttribute("max",config.ws_cnt-1);
start.value = segstate.start;
start.addEventListener('change', ()=>{
segstate.start = start.value;
ws_send("S[" + segstate.start);
});
var stop = document.getElementById("segstop");
stop.setAttribute("max",config.ws_cnt-1);
stop.value = segstate.stop;
stop.addEventListener('change', ()=>{
segstate.stop = stop.value;
ws_send("S]" + segstate.stop);
});
var count = document.getElementById("selectcount");
count.value = config.ws_cnt;
count.addEventListener('change', ()=>{
config.ws_cnt = count.value;
ws_send("Csc" + config.ws_cnt);
start.setAttribute("max",config.ws_cnt-1);
stop.setAttribute("max",config.ws_cnt-1);
});
var optrev = document.getElementById("selectoptrev"); var optrev = document.getElementById("selectoptrev");
for (var code in selectoptrev) { for (var code in selectoptrev) {
var option = document.createElement("OPTION"); var option = document.createElement("OPTION");
@@ -1767,10 +1876,10 @@ function initSettings() {
option.innerHTML = selectoptrev[code]; option.innerHTML = selectoptrev[code];
optrev.appendChild(option); optrev.appendChild(option);
} }
optrev.value = (config.ws_fxopt & 128); optrev.value = (segstate.ws_fxopt & 128);
optrev.addEventListener('change', ()=>{ optrev.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value; segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt); ws_send("So" + segstate.ws_fxopt);
}); });
var optfade = document.getElementById("selectoptfade"); var optfade = document.getElementById("selectoptfade");
for (var code in selectoptfade) { for (var code in selectoptfade) {
@@ -1779,10 +1888,10 @@ function initSettings() {
option.innerHTML = selectoptfade[code]; option.innerHTML = selectoptfade[code];
optfade.appendChild(option); optfade.appendChild(option);
} }
optfade.value = (config.ws_fxopt & 112); optfade.value = (segstate.ws_fxopt & 112);
optfade.addEventListener('change', ()=>{ optfade.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value; segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt); ws_send("So" + segstate.ws_fxopt);
}); });
var optgamma = document.getElementById("selectoptgamma"); var optgamma = document.getElementById("selectoptgamma");
for (var code in selectoptgamma) { for (var code in selectoptgamma) {
@@ -1791,10 +1900,10 @@ function initSettings() {
option.innerHTML = selectoptgamma[code]; option.innerHTML = selectoptgamma[code];
optgamma.appendChild(option); optgamma.appendChild(option);
} }
optgamma.value = (config.ws_fxopt & 8); optgamma.value = (segstate.ws_fxopt & 8);
optgamma.addEventListener('change', ()=>{ optgamma.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value; segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt); ws_send("So" + segstate.ws_fxopt);
}); });
var optsize = document.getElementById("selectoptsize"); var optsize = document.getElementById("selectoptsize");
for (var code in selectoptsize) { for (var code in selectoptsize) {
@@ -1803,10 +1912,10 @@ function initSettings() {
option.innerHTML = selectoptsize[code]; option.innerHTML = selectoptsize[code];
optsize.appendChild(option); optsize.appendChild(option);
} }
optsize.value = (config.ws_fxopt & 6) optsize.value = (segstate.ws_fxopt & 6)
optsize.addEventListener('change', ()=>{ optsize.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value; segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt); ws_send("So" + segstate.ws_fxopt);
}); });
slavenodes.value = settings.slave_nodes; slavenodes.value = settings.slave_nodes;
lang.addEventListener('change', ()=>{ lang.addEventListener('change', ()=>{
@@ -1820,9 +1929,9 @@ function initSettings() {
redrawColorPicker(); redrawColorPicker();
}); });
var settransitionEffects = document.getElementById("set-transitionEffects"); var settransitionEffects = document.getElementById("set-transitionEffects");
settransitionEffects.checked = config.transitionEffects; settransitionEffects.checked = config.ws_trans;
settransitionEffects.addEventListener('change', ()=>{ settransitionEffects.addEventListener('change', ()=>{
config.transitionEffects = settransitionEffects.checked; config.ws_trans = settransitionEffects.checked;
if (settransitionEffects.checked) { if (settransitionEffects.checked) {
document.getElementById("settransitionEffectsbgcolor").style.backgroundColor = settings.theme_btn; document.getElementById("settransitionEffectsbgcolor").style.backgroundColor = settings.theme_btn;
ws_send("Ce1"); ws_send("Ce1");
@@ -1855,6 +1964,7 @@ function initSettings() {
settings.theme_back = colback.value; settings.theme_back = colback.value;
document.getElementById("container").style.backgroundColor = settings.theme_back; document.getElementById("container").style.backgroundColor = settings.theme_back;
document.getElementById("language").style.backgroundColor = settings.theme_back; document.getElementById("language").style.backgroundColor = settings.theme_back;
document.getElementById("selectseg").style.backgroundColor = settings.theme_back;
document.getElementById("selectrgbo").style.backgroundColor = settings.theme_back; document.getElementById("selectrgbo").style.backgroundColor = settings.theme_back;
document.getElementById("selectoptrev").style.backgroundColor = settings.theme_back; document.getElementById("selectoptrev").style.backgroundColor = settings.theme_back;
document.getElementById("selectoptfade").style.backgroundColor = settings.theme_back; document.getElementById("selectoptfade").style.backgroundColor = settings.theme_back;
@@ -1867,6 +1977,7 @@ function initSettings() {
for (var i = 0; i < icons.length; i++) { for (var i = 0; i < icons.length; i++) {
icons[i].style.color = (yiq >= 125) ? '#222' : '#EEE'; icons[i].style.color = (yiq >= 125) ? '#222' : '#EEE';
} }
document.getElementById("selectSegLbl").style.color = (yiq >= 125) ? '#111' : '#EEE';
document.getElementById("wsmessageLbl").style.color = (yiq >= 125) ? '#111' : '#EEE'; document.getElementById("wsmessageLbl").style.color = (yiq >= 125) ? '#111' : '#EEE';
document.getElementById("redNum").style.color = (yiq >= 125) ? '#111' : '#EEE'; document.getElementById("redNum").style.color = (yiq >= 125) ? '#111' : '#EEE';
document.getElementById("greenNum").style.color = (yiq >= 125) ? '#111' : '#EEE'; document.getElementById("greenNum").style.color = (yiq >= 125) ? '#111' : '#EEE';
@@ -2018,8 +2129,8 @@ function ws_reconnect() {
function ws_connect() { function ws_connect() {
data.connection = new ReconnectingWebSocket(ws_url, "arduino", ws_options); data.connection = new ReconnectingWebSocket(ws_url, "arduino", ws_options);
document.getElementById("percentage").innerHTML = "67%"; document.getElementById("percentage").innerHTML = "75%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "67,100"); document.getElementById("percentage-done").setAttribute("stroke-dasharray", "75,100");
document.getElementById("modal-content").innerHTML = language[settings.lang].loadWebsock; document.getElementById("modal-content").innerHTML = language[settings.lang].loadWebsock;
// When the connection is open, send some data to the server // When the connection is open, send some data to the server
@@ -2031,12 +2142,12 @@ function ws_connect() {
con.className = "hidden"; con.className = "hidden";
con = document.getElementById("connected"); con = document.getElementById("connected");
con.className = con.className = ""; con.className = con.className = "";
document.getElementById("percentage").innerHTML = "100%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "100,100");
document.getElementById("modal-content").innerHTML = language[settings.lang].loadReady;
//setTimeout(function() { ws_send("$"); }, 2000); //setTimeout(function() { ws_send("$"); }, 2000);
//setTimeout(function() { ws_send("C"); }, 3000); //setTimeout(function() { ws_send("C"); }, 3000);
//setTimeout(function() { ws_send("~"); }, 4000); //setTimeout(function() { ws_send("~"); }, 4000);
document.getElementById("percentage").innerHTML = "100%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "100,100");
document.getElementById("modal-content").innerHTML = language[settings.lang].loadReady;
}; };
// When the connection is open, send some data to the server // When the connection is open, send some data to the server
@@ -2069,53 +2180,56 @@ function ws_connect() {
// document.getElementById('modal').style.display = "none"; // document.getElementById('modal').style.display = "none";
// console.log("res", res); // console.log("res", res);
if (res) { if (res) {
// Status starts here if (typeof res.segment !== "undefined") { state.segment= res.segment; document.getElementById("selectseg").value = state.segment; }
if (typeof res.mode !== "undefined") data.mode = res.mode; if (typeof res.mode !== "undefined") { state.mode = res.mode; }
if (typeof res.ws2812fx_mode !== "undefined") data.ws2812fx_mode = res.ws2812fx_mode;
if (typeof res.speed !== "undefined") {
data.speed = res.speed;
// init SliderVals
speed.value = res.speed;
}
if (typeof res.brightness !== "undefined") { if (typeof res.brightness !== "undefined") {
data.brightness = res.brightness; state.brightness = res.brightness;
// init ColorSliderVals // init ColorSliderVals
bright.value = res.brightness; bright.value = res.brightness;
} }
// Segment Status starts here
if (typeof res.start !== "undefined") { segstate.start= res.start; document.getElementById("segstart").value = segstate.start; }
if (typeof res.stop !== "undefined") { segstate.stop = res.stop; document.getElementById("segstop").value = segstate.stop; }
if (typeof res.fx_mode !== "undefined") { segstate.mode = res.fx_mode; }
if (typeof res.speed !== "undefined") {
segstate.speed = res.speed;
// init SliderVals
speed.value = res.speed;
}
if (typeof res.color !== "undefined") { if (typeof res.color !== "undefined") {
data.color.w = res.color[0]; segstate.color.w = res.color[0];
data.color.r = res.color[1]; segstate.color.r = res.color[1];
data.color.g = res.color[2]; segstate.color.g = res.color[2];
data.color.b = res.color[3]; segstate.color.b = res.color[3];
data.color.hex = rgbToHex([res.color[0], res.color[1], res.color[2], res.color[3]]); segstate.color.hex = rgbToHex([res.color[0], res.color[1], res.color[2], res.color[3]]);
data.color.w2 = res.color[4]; segstate.color.w2 = res.color[4];
data.color.r2 = res.color[5]; segstate.color.r2 = res.color[5];
data.color.g2 = res.color[6]; segstate.color.g2 = res.color[6];
data.color.b2 = res.color[7]; segstate.color.b2 = res.color[7];
data.color.hex2 = rgbToHex([res.color[4], res.color[5], res.color[6], res.color[7]]); segstate.color.hex2 = rgbToHex([res.color[4], res.color[5], res.color[6], res.color[7]]);
data.color.w3 = res.color[8]; segstate.color.w3 = res.color[8];
data.color.r3 = res.color[9]; segstate.color.r3 = res.color[9];
data.color.g3 = res.color[10]; segstate.color.g3 = res.color[10];
data.color.b3 = res.color[11]; segstate.color.b3 = res.color[11];
data.color.hex3 = rgbToHex([res.color[8], res.color[9], res.color[10], res.color[11]]); segstate.color.hex3 = rgbToHex([res.color[8], res.color[9], res.color[10], res.color[11]]);
// init ColorSliderVals // init ColorSliderVals
if (data.color_num === 1) { if (data.color_num === 1) {
red.value = data.color.r; red.value = segstate.color.r;
green.value = data.color.g; green.value = segstate.color.g;
blue.value = data.color.b; blue.value = segstate.color.b;
white.value = data.color.w; white.value = segstate.color.w;
} }
if (data.color_num === 2) { if (data.color_num === 2) {
red.value = data.color.r2; red.value = segstate.color.r2;
green.value = data.color.g2; green.value = segstate.color.g2;
blue.value = data.color.b2; blue.value = segstate.color.b2;
white.value = data.color.w2; white.value = segstate.color.w2;
} }
if (data.color_num === 3) { if (data.color_num === 3) {
red.value = data.color.r3; red.value = segstate.color.r3;
green.value = data.color.g3; green.value = segstate.color.g3;
blue.value = data.color.b3; blue.value = segstate.color.b3;
white.value = data.color.w3; white.value = segstate.color.w3;
} }
} }
// Config starts here // Config starts here
@@ -2124,6 +2238,7 @@ function ws_connect() {
if (typeof res.mqtt_port !== "undefined") { config.mqtt_port = res.mqtt_port; document.getElementById("mqtt_port").value = config.mqtt_port; } if (typeof res.mqtt_port !== "undefined") { config.mqtt_port = res.mqtt_port; document.getElementById("mqtt_port").value = config.mqtt_port; }
if (typeof res.mqtt_user !== "undefined") { config.mqtt_user = res.mqtt_user; document.getElementById("mqtt_user").value = config.mqtt_user; } if (typeof res.mqtt_user !== "undefined") { config.mqtt_user = res.mqtt_user; document.getElementById("mqtt_user").value = config.mqtt_user; }
if (typeof res.mqtt_pass !== "undefined") { config.mqtt_pass = res.mqtt_pass; document.getElementById("mqtt_pass").value = config.mqtt_pass; } if (typeof res.mqtt_pass !== "undefined") { config.mqtt_pass = res.mqtt_pass; document.getElementById("mqtt_pass").value = config.mqtt_pass; }
if (typeof res.ws_seg !== "undefined") { config.ws_seg = res.ws_seg; document.getElementById("selectsegcnt").value = config.ws_seg; }
if (typeof res.ws_cnt !== "undefined") { config.ws_cnt = res.ws_cnt; document.getElementById("selectcount").value = config.ws_cnt; } if (typeof res.ws_cnt !== "undefined") { config.ws_cnt = res.ws_cnt; document.getElementById("selectcount").value = config.ws_cnt; }
if (typeof res.ws_rgbo !== "undefined") { if (typeof res.ws_rgbo !== "undefined") {
config.ws_rgbo = res.ws_rgbo; config.ws_rgbo = res.ws_rgbo;
@@ -2134,19 +2249,20 @@ function ws_connect() {
} else { } else {
document.getElementById("white").parentNode.className = "hidden"; document.getElementById("white").parentNode.className = "hidden";
white.value = 0; white.value = 0;
data.color.w = 0; segstate.color.w = 0;
data.color.w2 = 0; segstate.color.w2 = 0;
data.color.w3 = 0; segstate.color.w3 = 0;
} }
} }
if (typeof res.ws_pin !== "undefined") { config.ws_pin = res.ws_pin; document.getElementById("selectpin").value = config.ws_pin; } if (typeof res.ws_pin !== "undefined") { config.ws_pin = res.ws_pin; document.getElementById("selectpin").value = config.ws_pin; }
if (typeof res.ws_trans !== "undefined") { config.ws_trans = res.ws_trans; document.getElementById("set-transitionEffects").value = config.ws_trans; }
if (typeof res.ws_fxopt !== "undefined") { if (typeof res.ws_fxopt !== "undefined") {
config.ws_fxopt = res.ws_fxopt; segstate.ws_fxopt = res.ws_fxopt;
document.getElementById("selectoptrev").value = (config.ws_fxopt & 128); document.getElementById("selectoptrev").value = (segstate.ws_fxopt & 128);
document.getElementById("selectoptfade").value = (config.ws_fxopt & 112); document.getElementById("selectoptfade").value = (segstate.ws_fxopt & 112);
document.getElementById("selectoptgamma").value = (config.ws_fxopt & 8); document.getElementById("selectoptgamma").value = (segstate.ws_fxopt & 8);
document.getElementById("selectoptsize").value = (config.ws_fxopt & 6); document.getElementById("selectoptsize").value = (segstate.ws_fxopt & 6);
} }
// Modes starts here // Modes starts here
if (typeof res[0] !== "undefined") { if (typeof res[0] !== "undefined") {
@@ -2157,18 +2273,22 @@ function ws_connect() {
}); });
} }
// init Color Vals // init Color Vals
colorNumrVals(); colorNumVals();
initSliderColors(); initSliderColors();
// init Change Range Val // init Change Range Val
changeRangeNumVal(); changeRangeNumVal();
// init Colors controls // init Colors controls
// init display Colors // init display Colors
displayColors(true); displayColors(true);
console.log("displayColors finished!");
select_active_button(); select_active_button();
console.log("select_active_button finished!");
} }
if (data.init === true) { console.log("data.init: ", data.init);
if (data.init == true) {
console.log("Initializing...");
// Set selected mode button // Set selected mode button
//document.getElementById(data.ws2812fx_mode).style.backgroundColor = settings.theme_btnsel; //document.getElementById(segstate.mode).style.backgroundColor = settings.theme_btnsel;
// Close Loading Modal // Close Loading Modal
setTimeout(() => { setTimeout(() => {
document.getElementById('modal').style.display = "none"; document.getElementById('modal').style.display = "none";
@@ -2212,38 +2332,45 @@ function select_active_button() {
for (i = 0; i < btns.length; i++) { for (i = 0; i < btns.length; i++) {
btns[i].style.backgroundColor = settings.theme_btn; btns[i].style.backgroundColor = settings.theme_btn;
} }
if (data.mode != 1 || (data.mode === 1 && data.ws2812fx_mode !== 57)) { // CUSTOM WS MODE if (state.mode != 1 || (state.mode == 1 && segstate.mode != 57)) { // CUSTOM WS MODE
wsmess = document.getElementById("message"); wsmess = document.getElementById("message");
var arr = wsmess.className.split(" "); var arr = wsmess.className.split(" ");
if (arr.indexOf("hidden") === -1) { if (arr.indexOf("hidden") === -1) {
wsmess.className += " hidden"; wsmess.className += " hidden";
} }
segments = document.getElementById("segments");
segments.className = segments.className.replace(/\b hidden\b/g, "");
} }
if (data.mode >= 1) { if (state.mode >= 1) {
document.getElementById(data.ws2812fx_mode).style.backgroundColor = settings.theme_btnsel; document.getElementById(segstate.mode).style.backgroundColor = settings.theme_btnsel;
if (data.ws2812fx_mode === 56) { // AUTOPLAY if (segstate.mode == 56) { // AUTOPLAY
disable_modebuttons(false); disable_modebuttons(false);
disable_color_selection(true); disable_color_selection(true);
disable_bright_selection(false); disable_bright_selection(false);
disable_speed_selection(true); disable_speed_selection(true);
} else if (data.ws2812fx_mode === 57) { //CUSTOM_WS } else if (segstate.mode == 57) { //CUSTOM_WS
wsmess = document.getElementById("message"); wsmess = document.getElementById("message");
wsmess.className = wsmess.className.replace(/\b hidden\b/g, ""); wsmess.className = wsmess.className.replace(/\b hidden\b/g, "");
sements = document.getElementById("segments");
var arr = segments.className.split(" ");
if (arr.indexOf("hidden") === -1) {
segments.className += " hidden";
}
disable_modebuttons(false); disable_modebuttons(false);
disable_color_selection(true); disable_color_selection(true);
disable_bright_selection(false); disable_bright_selection(false);
disable_speed_selection(true); disable_speed_selection(true);
} else if (data.ws2812fx_mode === 58) { //TV } else if (segstate.mode == 58) { //TV
disable_modebuttons(false); disable_modebuttons(false);
disable_color_selection(true); disable_color_selection(true);
disable_bright_selection(false); disable_bright_selection(false);
disable_speed_selection(false); disable_speed_selection(false);
} else if (data.ws2812fx_mode === 59) { //E1.31 } else if (segstate.mode == 59) { //E1.31
disable_modebuttons(false); disable_modebuttons(false);
disable_color_selection(true); disable_color_selection(true);
disable_bright_selection(false); disable_bright_selection(false);
disable_speed_selection(true); disable_speed_selection(true);
} else if (data.ws2812fx_mode === 60) { //Fire2012 } else if (segstate.mode == 60) { //Fire2012
disable_modebuttons(false); disable_modebuttons(false);
disable_color_selection(true); disable_color_selection(true);
disable_bright_selection(false); disable_bright_selection(false);
@@ -2254,7 +2381,7 @@ function select_active_button() {
disable_bright_selection(false); disable_bright_selection(false);
disable_speed_selection(false); disable_speed_selection(false);
} }
} else if (data.mode === 0) { } else if (state.mode == 0) {
document.getElementById("off").style.backgroundColor = settings.theme_btnsel; document.getElementById("off").style.backgroundColor = settings.theme_btnsel;
disable_modebuttons(false); disable_modebuttons(false);
disable_color_selection(true); disable_color_selection(true);
@@ -2282,32 +2409,32 @@ function disable_modebuttons(status) {
function set_mode(mode_id) { function set_mode(mode_id) {
if (Number.isInteger(mode_id)) { if (Number.isInteger(mode_id)) {
data.mode = 1; state.mode = 1;
data.ws2812fx_mode = mode_id; segstate.mode = mode_id;
} else { } else {
// For named modes // For named modes
if (mode_id == "off") { if (mode_id == "off") {
data.mode = 0; state.mode = 0;
} }
} }
select_active_button(); select_active_button();
ws_send("/" + mode_id); ws_send("/" + mode_id);
} }
function set_speed() { function set_speed() {
ws_send("?" + data.speed); ws_send("?" + segstate.speed);
} }
function set_brightness() { function set_brightness() {
ws_send("%" + data.brightness); ws_send("%" + state.brightness);
} }
function set_color() { function set_color() {
if (data.color_num === 1) { if (data.color_num === 1) {
ws_send("#" + rgbToHex([data.color.w, data.color.r, data.color.g, data.color.b])); ws_send("#" + rgbToHex([segstate.color.w, segstate.color.r, segstate.color.g, segstate.color.b]));
} }
if (data.color_num === 2) { if (data.color_num === 2) {
ws_send("##" + rgbToHex([data.color.w2, data.color.r2, data.color.g2, data.color.b2])); ws_send("##" + rgbToHex([segstate.color.w2, segstate.color.r2, segstate.color.g2, segstate.color.b2]));
} }
if (data.color_num === 3) { if (data.color_num === 3) {
ws_send("###" + rgbToHex([data.color.w3, data.color.r3, data.color.g3, data.color.b3])); ws_send("###" + rgbToHex([segstate.color.w3, segstate.color.r3, segstate.color.g3, segstate.color.b3]));
} }
} }
@@ -2345,11 +2472,11 @@ function onSelectColor(event) {
var color = context.getImageData(pos.x, pos.y, 1, 1).data; var color = context.getImageData(pos.x, pos.y, 1, 1).data;
var hex_color = rgbToHex(color); var hex_color = rgbToHex(color);
var colnum = (data.color_num === 1) ? "" : data.color_num; var colnum = (data.color_num === 1) ? "" : data.color_num;
data.color["hex" + colnum] = hex_color; segstate.color["hex" + colnum] = hex_color;
data.color["r" + colnum] = color[0]; segstate.color["r" + colnum] = color[0];
data.color["g" + colnum] = color[1]; segstate.color["g" + colnum] = color[1];
data.color["b" + colnum] = color[2]; segstate.color["b" + colnum] = color[2];
data.color["w" + colnum] = 0; segstate.color["w" + colnum] = 0;
red.value = color[0]; red.value = color[0];
green.value = color[1]; green.value = color[1];
blue.value = color[2]; blue.value = color[2];
@@ -2357,7 +2484,7 @@ function onSelectColor(event) {
displayColors(); displayColors();
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
} }
} }
function redrawColorPicker() { function redrawColorPicker() {
@@ -2525,13 +2652,11 @@ document.addEventListener("DOMContentLoaded", function(event) {
getModes(); getModes();
readSettings(); readSettings();
ws_connect(); ws_connect();
ws_send("$") ws_send("$");
document.getElementById("modal-content").innerHTML = language.en.loadModes;
//ws_send("C"); //ws_send("C");
getConfig(); getConfig();
canvas.width = 400; canvas.width = 400;
canvas.height = 400; canvas.height = 400;
redrawColorPicker(); redrawColorPicker();
}); });
</script> </script>
Binary file not shown.
+53 -40
View File
@@ -12,30 +12,33 @@
#define FX_OPTIONS 48 // ws2812fx Options 48 = SIZE_SMALL + FADE_MEDIUM is configurable just for the start; for WS2812FX setSegment OPTIONS, see: https://github.com/kitesurfer1404/WS2812FX/blob/master/extras/WS2812FX%20Users%20Guide.md #define FX_OPTIONS 48 // ws2812fx Options 48 = SIZE_SMALL + FADE_MEDIUM is configurable just for the start; for WS2812FX setSegment OPTIONS, see: https://github.com/kitesurfer1404/WS2812FX/blob/master/extras/WS2812FX%20Users%20Guide.md
//#define LED_TYPE_WS2811 // Uncomment, if LED type uses 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) //#define LED_TYPE_WS2811 // Uncomment, if LED type uses 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
#define LED_BUILTIN 2 // ESP-12F has the built in LED on GPIO2, see https://github.com/esp8266/Arduino/issues/2192 #define LED_BUILTIN 2 // ESP-12F has the built in LED on GPIO2, see https://github.com/esp8266/Arduino/issues/2192
char HOSTNAME[65] = "McLightingRGBW"; // Friedly hostname is configurable just for the start. Hostname should not contain spaces as this can break Home Assistant discovery if used. char HOSTNAME[65] = "McLightingRGBW"; // Friedly hostname is configurable just for the start. Hostname should not contain spaces as this can break Home Assistant discovery if used.
#define ENABLE_OTA 1 // If defined, enable Arduino OTA code. If set to 0 enable Arduino OTA code, if set to 1 enable ESP8266HTTPUpdateServer OTA code. #define ENABLE_OTA 1 // If defined, enable Arduino OTA code. If set to 0 enable Arduino OTA code, if set to 1 enable ESP8266HTTPUpdateServer OTA code.
#define ENABLE_MQTT 1 // If defined use MQTT OR AMQTT, if set to 0 enable MQTT client code, see: https://github.com/toblum/McLighting/wiki/MQTT-API, if set to 1, enable Async MQTT code, see: https://github.com/marvinroger/async-mqtt-client #define ENABLE_MQTT 1 // If defined use MQTT OR AMQTT, if set to 0 enable MQTT client code, see: https://github.com/toblum/McLighting/wiki/MQTT-API, if set to 1, enable Async MQTT code, see: https://github.com/marvinroger/async-mqtt-client
//#define ENABLE_MQTT_HOSTNAME_CHIPID // Uncomment/comment to add ESPChipID to end of MQTT hostname //#define ENABLE_MQTT_HOSTNAME_CHIPID // Uncomment/comment to add ESPChipID to end of MQTT hostname
//#define ENABLE_MQTT_INCLUDE_IP // uncomment/comment to add the IP-adress to the MQTT message
#define ENABLE_HOMEASSISTANT // If defined, enable Homeassistant integration, ENABLE_MQTT must be active #define ENABLE_HOMEASSISTANT // If defined, enable Homeassistant integration, ENABLE_MQTT must be active
#define MQTT_HOME_ASSISTANT_SUPPORT // If defined, use AMQTT and select Tools -> IwIP Variant -> Higher Bandwidth #define MQTT_HOME_ASSISTANT_SUPPORT // If defined, use AMQTT and select Tools -> IwIP Variant -> Higher Bandwidth
#define ENABLE_BUTTON 14 // If defined, enable button handling code, see: https://github.com/toblum/McLighting/wiki/Button-control, the value defines the input pin (14 / D5) for switching the LED strip on / off, connect this PIN to ground to trigger button. #define ENABLE_BUTTON 14 // If defined, enable button handling code, see: https://github.com/toblum/McLighting/wiki/Button-control, the value defines the input pin (14 / D5) for switching the LED strip on / off, connect this PIN to ground to trigger button.
//#define ENABLE_BUTTON_GY33 12 // If defined, enable button handling code for GY-33 color sensor to scan color. The value defines the input pin (12 / D6) for read color data with RGB sensor, connect this PIN to ground to trigger button. //#define ENABLE_BUTTON_GY33 12 // If defined, enable button handling code for GY-33 color sensor to scan color. The value defines the input pin (12 / D6) for read color data with RGB sensor, connect this PIN to ground to trigger button.
//#define POWER_SUPPLY 12 // PIN (12 / D6) If defined, enable output to control external power supply
//#define ENABLE_REMOTE 13 // If defined, enable Remote Control via TSOP31238. The value defines the input pin (13 / D7) for TSOP31238 Out
#if defined(ENABLE_BUTTON_GY33) #if defined(ENABLE_BUTTON_GY33)
#define GAMMA 2.5 // Gamma correction for GY-33 sensor #define GAMMA 2.5 // Gamma correction for GY-33 sensor
#endif #endif
#define ENABLE_REMOTE 13 // If defined, enable Remote Control via TSOP31238. The value defines the input pin (13 / D7) for TSOP31238 Out
#define ENABLE_STATE_SAVE 1 // If defined, load saved state on reboot and save state. If set to 0 from EEPROM, if set to 1 from SPIFFS #define ENABLE_STATE_SAVE // If defined, load saved state on reboot and save state on SPIFFS
#define CUSTOM_WS2812FX_ANIMATIONS // uncomment and put animations in "custom_ws2812fx_animations.h" #define CUSTOM_WS2812FX_ANIMATIONS // uncomment and put animations in "custom_ws2812fx_animations.h"
#define USE_HTML_MIN_GZ // uncomment for using index.htm & edit.htm from PROGMEM instead of SPIFFs #define USE_HTML_MIN_GZ // uncomment for using index.htm & edit.htm from PROGMEM instead of SPIFFS
#define TRANS_COLOR_DELAY 5 // Delay for color transition #define TRANS_COLOR_DELAY 5 // Delay for color transition
#define TRANS_DELAY 10 // Delay for brightness and speed transition #define TRANS_DELAY 10 // Delay for brightness and speed transition
bool transEffect = false; // Experimental: Enable transitions of color, brightness and speed. It does not work properly for all effects. // Experimental: Enable transitions of color, brightness and speed. It does not work properly for all effects.
bool transEffectOverride = false; bool transEffectOverride = false;
uint8_t trans_cnt = 0; uint8_t trans_cnt = 0;
int trans_cnt_max = 0; int trans_cnt_max = 0;
@@ -49,7 +52,8 @@ unsigned long speedFadeDelay = 0;
uint8_t END_UNIVERSE = START_UNIVERSE; // Total number of Universes to listen for, starting at UNIVERSE uint8_t END_UNIVERSE = START_UNIVERSE; // Total number of Universes to listen for, starting at UNIVERSE
#endif #endif
uint8_t selected_segment = 0; uint8_t prevsegment = 0;
#if defined(ENABLE_REMOTE) #if defined(ENABLE_REMOTE)
uint8_t selected_color = 1; uint8_t selected_color = 1;
uint64_t last_remote_cmd; uint64_t last_remote_cmd;
@@ -92,9 +96,9 @@ uint8_t selected_segment = 0;
// parameters for automatically cycling favorite patterns // parameters for automatically cycling favorite patterns
uint32_t autoParams[][6] = { // main_color, back_color, xtra_color, speed, mode, duration (milliseconds) uint32_t autoParams[][6] = { // main_color, back_color, xtra_color, speed, mode, duration (milliseconds)
{0x00ff0000, 0x0000ff00, 0x00000000, 200, 1, 5000}, // blink red/geen for 5 seconds {0x00ff0000, 0x0000ff00, 0x00000000, 200, 1, 5000}, // blink red/geen for 5 seconds
{0x0000ff00, 0x000000ff, 0x00000000, 200, 3, 10000}, // wipe green/blue for 10 seconds {0x0000ff00, 0x000000ff, 0x00000000, 180, 3, 10000}, // wipe green/blue for 10 seconds
{0x000000ff, 0x00ff0000, 0x00000000, 60, 14, 10000}, // dual scan blue on red for 10 seconds {0x000000ff, 0x00ff0000, 0x00000000, 100, 14, 10000}, // dual scan blue on red for 10 seconds
{0x000000ff, 0x00ff0000, 0x00000000, 40, 45, 15000}, // fireworks blue/red for 15 seconds {0x000000ff, 0x00ff0000, 0x00000000, 100, 45, 15000}, // fireworks blue/red for 15 seconds
{0x00ff0000, 0x0000ff00, 0x000000ff, 40, 54, 15000} // tricolor chase red/green/blue for 15 seconds {0x00ff0000, 0x0000ff00, 0x000000ff, 40, 54, 15000} // tricolor chase red/green/blue for 15 seconds
}; };
@@ -140,21 +144,51 @@ uint32_t autoParams[][6] = { // main_color, back_color, xtra_color, speed, mod
// *************************************************************************** // ***************************************************************************
#define DBG_OUTPUT_PORT Serial // Set debug output port #define DBG_OUTPUT_PORT Serial // Set debug output port
uint8_t autoCount[10] = {}; // Global variable for storing the counter for automated playback for each segment
unsigned long autoDelay[10] = {}; // Global variable for storing the time to next auto effect for each segment
struct {
uint16_t start = 0;
uint16_t stop = NUMLEDS - 1;
uint8_t mode[10] = {}; // Global variable for storing the WS2812FX mode to set for each segment
uint8_t speed[10] = {}; // Global variable for storing the speed for effects --> smaller == slower
uint32_t colors[10][3] = {}; // 2 dim. Color array for setting colors of WS2812FX
uint8_t options = FX_OPTIONS;
} segState;
// List of all color modes // List of all color modes
enum MODE {OFF, HOLD, SET, INIT_STRIP}; enum MODE {OFF, HOLD, SET};
MODE mode = SET; // Standard mode that is active when software starts
MODE prevmode = HOLD; // Do not change MODE prevmode = HOLD; // Do not change
uint8_t autoCount = 0; // Global variable for storing the counter for automated playback struct {
long autoDelay = 0; // Global variable for storing the time to next auto effect uint8_t segment = 0; // Actual selected segment
uint8_t ws2812fx_speed = 196; // Global variable for storing the speed for effects --> smaller == slower MODE mode = SET; // Standard mode that is active when software starts
uint8_t ws2812fx_speed_actual = 196; // Global variable for storing the speed for effects while fading --> smaller == slower
uint8_t brightness = 196; // Global variable for storing the brightness (255 == 100%) uint8_t brightness = 196; // Global variable for storing the brightness (255 == 100%)
uint8_t brightness_trans = 0; // Global variable for storing the brightness before change } State;
uint8_t ws2812fx_mode = 0; // Global variable for storing the WS2812FX mode to set
uint32_t hex_colors[3] = {}; // Color array for setting colors of WS2812FX struct {
uint32_t hex_colors_trans[3] = {}; // Color array of colors of WS2812FX before fading uint8_t segments = 1;
uint16_t stripSize = NUMLEDS;
char RGBOrder[5] = RGBORDER;
#if defined(USE_WS2812FX_DMA)
#if USE_WS2812FX_DMA == 0
uint8_t pin = 3;
#endif
#if USE_WS2812FX_DMA == 1
uint8_t pin = 2;
#endif
#if USE_WS2812FX_DMA == 2
uint8_t pin = 1;
#endif
#else
uint8_t pin = LED_PIN;
#endif
bool transEffect = false;
} Config;
uint8_t fx_speed = 196; // Global variable for storing the speed for effects while fading --> smaller == slower
uint8_t fx_mode = 0;
uint8_t brightness_trans = 0; // Global variable for storing the brightness before change
uint32_t hexcolors_trans[3] = {}; // Color array of colors of WS2812FX before fading
struct ledstate // Data structure to store a state of a single led struct ledstate // Data structure to store a state of a single led
{ {
uint8_t red; uint8_t red;
@@ -170,8 +204,6 @@ LEDState back_color = { 0, 0, 0, 0 }; // Store the "2nd color" of the strip u
LEDState xtra_color = { 0, 0, 0, 0 }; // Store the "3rd color" of the strip used in single color modes LEDState xtra_color = { 0, 0, 0, 0 }; // Store the "3rd color" of the strip used in single color modes
bool updateConfig = false; // For WiFiManger custom config and config bool updateConfig = false; // For WiFiManger custom config and config
char last_state[67]; // Keeps the state representation before auto or off mode
bool updateState = false;
// Button handling // Button handling
@@ -196,22 +228,3 @@ bool updateState = false;
byte KeyPressCount_gy33 = 0; byte KeyPressCount_gy33 = 0;
byte prevKeyState_gy33 = HIGH; // button is active low byte prevKeyState_gy33 = HIGH; // button is active low
#endif #endif
struct {
uint16_t stripSize = NUMLEDS;
char RGBOrder[5] = RGBORDER;
#if defined(USE_WS2812FX_DMA)
#if USE_WS2812FX_DMA == 0
uint8_t pin = 3;
#endif
#if USE_WS2812FX_DMA == 1
uint8_t pin = 2;
#endif
#if USE_WS2812FX_DMA == 2
uint8_t pin = 1;
#endif
#else
uint8_t pin = LED_PIN;
#endif
uint8_t fxoptions = FX_OPTIONS;
} WS2812FXStripSettings;
+262
View File
@@ -0,0 +1,262 @@
#if defined(ENABLE_STATE_SAVE)
Ticker save_state;
Ticker save_seg_state;
Ticker save_conf;
bool updateState = false;
bool updateSegState = false;
void tickerSaveState(){
updateState = true;
}
void tickerSaveConfig(){
updateConfig = true;
}
void tickerSaveSegmentState(){
updateSegState = true;
}
// Write configuration to FS JSON
bool writeConfigFS(bool save){
if (save) {
//FS save
DBG_OUTPUT_PORT.println("Saving config: ");
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
DBG_OUTPUT_PORT.println("Failed!");
save_conf.detach();
updateConfig = false;
return false;
}
DBG_OUTPUT_PORT.println(listConfigJSON());
configFile.print(listConfigJSON());
configFile.close();
save_conf.detach();
updateConfig = false;
return true;
//end save
} else {
DBG_OUTPUT_PORT.println("SaveConfig is false!");
return false;
}
}
// Read search_str to FS
bool readConfigFS() {
//read configuration from FS JSON
if (SPIFFS.exists("/config.json")) {
//file exists, reading and loading
DBG_OUTPUT_PORT.print("Reading config file... ");
File configFile = SPIFFS.open("/config.json", "r");
if (configFile) {
DBG_OUTPUT_PORT.println("Opened!");
size_t size = configFile.size();
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
configFile.close();
#if defined(ENABLE_MQTT)
const size_t bufferSize = JSON_OBJECT_SIZE(11) + 150;
#else
const size_t bufferSize = JSON_OBJECT_SIZE(7) + 100;
#endif
DynamicJsonDocument jsonBuffer(bufferSize);
DeserializationError error = deserializeJson(jsonBuffer, buf.get());
DBG_OUTPUT_PORT.print("Config: ");
if (!error) {
DBG_OUTPUT_PORT.println("Parsed!");
JsonObject root = jsonBuffer.as<JsonObject>();
serializeJson(root, DBG_OUTPUT_PORT);
DBG_OUTPUT_PORT.println("");
strcpy(HOSTNAME, root["hostname"]);
#if defined(ENABLE_MQTT)
strcpy(mqtt_host, root["mqtt_host"]);
mqtt_port = root["mqtt_port"].as<uint16_t>();
strcpy(mqtt_user, root["mqtt_user"]);
strcpy(mqtt_pass, root["mqtt_pass"]);
#endif
Config.segments = constrain(root["ws_seg"].as<uint8_t>(), 1, MAX_NUM_SEGMENTS - 1);
Config.stripSize = constrain(root["ws_cnt"].as<uint16_t>(), 1, MAXLEDS);
char _rgbOrder[5];
strcpy(_rgbOrder, root["ws_rgbo"]);
checkRGBOrder(_rgbOrder);
uint8_t temp_pin;
checkPin((uint8_t) root["ws_pin"]);
Config.transEffect = root["ws_trans"].as<bool>();
jsonBuffer.clear();
return true;
} else {
DBG_OUTPUT_PORT.print("Failed to load json config: ");
DBG_OUTPUT_PORT.println(error.c_str());
jsonBuffer.clear();
}
} else {
DBG_OUTPUT_PORT.println("Failed to open /config.json");
}
} else {
DBG_OUTPUT_PORT.println("Coudnt find config.json");
writeConfigFS(true);
}
//end read
return false;
}
bool writeStateFS(bool save){
if (save) {
//save the strip state to FS JSON
DBG_OUTPUT_PORT.print("Saving state: ");
//SPIFFS.remove("/stripstate.json") ? DBG_OUTPUT_PORT.println("removed file") : DBG_OUTPUT_PORT.println("failed removing file");
File configFile = SPIFFS.open("/stripstate.json", "w");
if (!configFile) {
DBG_OUTPUT_PORT.println("Failed!");
save_state.detach();
updateState = false;
return false;
}
DBG_OUTPUT_PORT.println(listStateJSON());
configFile.print(listStateJSON());
configFile.close();
char filename[28];
save_state.detach();
updateState = false;
return true;
//end save
} else {
DBG_OUTPUT_PORT.println("SaveState is false!");
return false;
}
}
bool readStateFS() {
//read strip state from FS JSON
if (SPIFFS.exists("/stripstate.json")) {
//file exists, reading and loading
DBG_OUTPUT_PORT.print("Reading state file... ");
File configFile = SPIFFS.open("/stripstate.json", "r");
if (configFile) {
DBG_OUTPUT_PORT.println("Opened!");
size_t size = configFile.size();
// Allocate a buffer to store contents of the file.
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
configFile.close();
const size_t bufferSize = JSON_OBJECT_SIZE(3) + 50;
DynamicJsonDocument jsonBuffer(bufferSize);
DeserializationError error = deserializeJson(jsonBuffer, buf.get());
DBG_OUTPUT_PORT.print("Config: ");
if (!error) {
DBG_OUTPUT_PORT.print("Parsed");
JsonObject root = jsonBuffer.as<JsonObject>();
serializeJson(root, DBG_OUTPUT_PORT);
DBG_OUTPUT_PORT.println("");
State.segment = root["segment"];
State.mode = static_cast<MODE>(root["mode"].as<uint8_t>());
State.brightness = root["brightness"];
jsonBuffer.clear();
return true;
} else {
DBG_OUTPUT_PORT.print("Failed to load json config: ");
DBG_OUTPUT_PORT.println(error.c_str());
jsonBuffer.clear();
}
} else {
DBG_OUTPUT_PORT.println("Failed to open \"/stripstate.json\"");
}
} else {
DBG_OUTPUT_PORT.println("Couldn't find \"/stripstate.json\"");
writeStateFS(true);
}
//end read
return false;
}
bool writeSegmentStateFS(bool save, uint8_t seg){
if (save) {
//save the segment state to FS JSON
DBG_OUTPUT_PORT.print("Saving segment state: ");
char filename[28];
snprintf(filename, 28, "/stripstate_segment_%02i.json", seg);
filename[27] = 0x00;
File configFile = SPIFFS.open(filename, "w");
if (!configFile) {
DBG_OUTPUT_PORT.println("Failed!");
save_seg_state.detach();
updateSegState = false;
return false;
}
DBG_OUTPUT_PORT.println(listSegmentStateJSON(seg));
configFile.print(listSegmentStateJSON(seg));
configFile.close();
save_seg_state.detach();
updateSegState = false;
return true;
//end save
} else {
DBG_OUTPUT_PORT.println("SaveSegmentState is false!");
return false;
}
}
bool readSegmentStateFS(uint8_t _seg) {
//read strip state from FS JSON
char filename[28];
snprintf(filename, 28, "/stripstate_segment_%02i.json", _seg);
filename[27] = 0x00;
if (SPIFFS.exists(filename)) {
//file exists, reading and loading
DBG_OUTPUT_PORT.printf("Reading segmentstate file: %s\r\n", filename);
File configFile = SPIFFS.open(filename, "r");
if (configFile) {
DBG_OUTPUT_PORT.println("Opened!");
size_t size = configFile.size();
// Allocate a buffer to store contents of the file.
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
configFile.close();
const size_t bufferSize = JSON_ARRAY_SIZE(12) + JSON_OBJECT_SIZE(7) + 100;
DynamicJsonDocument jsonBuffer(bufferSize);
DeserializationError error = deserializeJson(jsonBuffer, buf.get());
DBG_OUTPUT_PORT.print("Config: ");
if (!error) {
DBG_OUTPUT_PORT.print("Parsed");
JsonObject root = jsonBuffer.as<JsonObject>();
serializeJson(root, DBG_OUTPUT_PORT);
DBG_OUTPUT_PORT.println("");
segState.start = constrain(root["start"].as<uint16_t>(), 0, Config.stripSize - 1) ;
segState.stop = constrain(root["stop"].as<uint16_t>(), 0, Config.stripSize - 1);
segState.mode[_seg] = root["fx_mode"].as<uint8_t>();
segState.speed[_seg] = root["speed"].as<uint8_t>();
main_color.white = root["color"][0].as<uint8_t>();
main_color.red = root["color"][1].as<uint8_t>();
main_color.green = root["color"][2].as<uint8_t>();
main_color.blue = root["color"][3].as<uint8_t>();
back_color.white = root["color"][4].as<uint8_t>();
back_color.red = root["color"][5].as<uint8_t>();
back_color.green = root["color"][6].as<uint8_t>();
back_color.blue = root["color"][7].as<uint8_t>();
xtra_color.white = root["color"][8].as<uint8_t>();
xtra_color.red = root["color"][9].as<uint8_t>();
xtra_color.green = root["color"][10].as<uint8_t>();
xtra_color.blue = root["color"][11].as<uint8_t>();
segState.options = constrain(root["ws_fxopt"].as<uint8_t>(), 0, 255) & 0xFE;
convertColors();
jsonBuffer.clear();
return true;
} else {
DBG_OUTPUT_PORT.print("Failed to load json config: ");
DBG_OUTPUT_PORT.println(error.c_str());
jsonBuffer.clear();
}
} else {
DBG_OUTPUT_PORT.printf("Failed to open \"/%s\"\r\n", filename);
}
} else {
DBG_OUTPUT_PORT.printf("Couldn't find \"/%s\"", filename);
writeSegmentStateFS(true, _seg);
}
//end read
return false;
}
#endif
+318
View File
@@ -0,0 +1,318 @@
// Prototypes
bool readSegmentStateFS(uint8_t _seg);
// End Prototypes
// Call convertColors whenever main_color, back_color or xtra_color changes.
void convertColors() {
hexcolors_trans[0] = (uint32_t)(main_color.white << 24) | (main_color.red << 16) | (main_color.green << 8) | main_color.blue;
hexcolors_trans[1] = (uint32_t)(back_color.white << 24) | (back_color.red << 16) | (back_color.green << 8) | back_color.blue;
hexcolors_trans[2] = (uint32_t)(xtra_color.white << 24) | (xtra_color.red << 16) | (xtra_color.green << 8) | xtra_color.blue;
}
/*uint32_t* convertColors2(uint8_t _w, uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _w2, uint8_t _r2, uint8_t _g2, uint8_t _b2, uint8_t _w3, uint8_t _r3, uint8_t _g3, uint8_t _b3) {
uint32_t _hexcolors[3] = {};
_hexcolors[0] = (uint32_t)(_w << 24) | (_r << 16) | (_g << 8) | _b;
_hexcolors[1] = (uint32_t)(_w2 << 24) | (_r2 << 16) | (_g2 << 8) | _b2;
_hexcolors[2] = (uint32_t)(_w3 << 24) | (_r3 << 16) | (_g3 << 8) | _b3;
return _hexcolors;
}*/
uint16_t convertSpeed(uint8_t _mcl_speed) {
uint16_t _fx_speed = 0;
if (_mcl_speed < 50) {
_fx_speed = 65535 - (_mcl_speed * 1000);
} else if (_mcl_speed < 100) {
_fx_speed = 16535 - ((_mcl_speed-49) * 250);
} else if (_mcl_speed < 150) {
_fx_speed = 4035 - ((_mcl_speed-99) * 50);
} else if (_mcl_speed < 200) {
_fx_speed = 1535 - ((_mcl_speed-149) * 25);
} else {
_fx_speed = 285 - ((_mcl_speed-199) * 5);
}
_fx_speed = constrain(_fx_speed, SPEED_MIN, SPEED_MAX);
return _fx_speed;
}
/*uint8_t unconvertSpeed(uint16_t _fx_speed) {
uint16_t _mcl_speed = 0;
if (_fx_speed <= 285) {
_mcl_speed = ((285 - _fx_speed)/5) + 199;
} else if (_fx_speed < 1535) {
_mcl_speed = ((1535 - _fx_speed)/25) + 149;
} else if (_fx_speed < 4035) {
_mcl_speed = ((4035 - _fx_speed)/50) + 99;
} else if (_mcl_speed < 16535) {
_mcl_speed = ((16535 - _fx_speed)/250) + 49;
} else {
_mcl_speed = ((65535 - _fx_speed)/1000);
}
return _mcl_speed;
}*/
bool checkPin(uint8_t pin) {
#if defined(USE_WS2812FX_DMA)
#if USE_WS2812FX_DMA == 0
pin = 3;
#endif
#if USE_WS2812FX_DMA == 1
pin = 1;
#endif
#if USE_WS2812FX_DMA == 2
pin = 2;
#endif
#endif
if (((pin >= 0 && pin <= 5) || (pin >= 12 && pin <= 16)) && (pin != Config.pin)) {
Config.pin = pin;
return true;
}
return false;
}
neoPixelType checkRGBOrder(char rgbOrder[5]) {
for( uint8_t i=0 ; i < sizeof(rgbOrder) ; ++i ) rgbOrder[i] = toupper(rgbOrder[i]) ;
DBG_OUTPUT_PORT.printf("Checking RGB Order: %s ...", rgbOrder);
neoPixelType returnOrder = 0;
if (strcmp(rgbOrder, "GRB") == 0) {
returnOrder = NEO_GRB;
} else if (strcmp(rgbOrder, "GBR") == 0) {
returnOrder = NEO_GBR;
} else if (strcmp(rgbOrder, "RGB") == 0) {
returnOrder = NEO_RGB;
} else if (strcmp(rgbOrder, "RBG") == 0) {
returnOrder = NEO_RBG;
} else if (strcmp(rgbOrder, "BRG") == 0) {
returnOrder = NEO_BRG;
} else if (strcmp(rgbOrder, "BGR") == 0) {
returnOrder = NEO_BGR;
} else if (strcmp(rgbOrder, "WGRB") == 0) {
returnOrder = NEO_WGRB;
} else if (strcmp(rgbOrder, "WGBR") == 0) {
returnOrder = NEO_WGBR;
} else if (strcmp(rgbOrder, "WRGB") == 0) {
returnOrder = NEO_WRGB;
} else if (strcmp(rgbOrder, "WRBG") == 0) {
returnOrder = NEO_WRBG;
} else if (strcmp(rgbOrder, "WBRG") == 0) {
returnOrder = NEO_WBRG;
} else if (strcmp(rgbOrder, "WBGR") == 0) {
returnOrder = NEO_WBGR;
} else if (strcmp(rgbOrder, "GWRB") == 0) {
returnOrder = NEO_GWRB;
} else if (strcmp(rgbOrder, "GWBR") == 0) {
returnOrder = NEO_GWBR;
} else if (strcmp(rgbOrder, "RWGB") == 0) {
returnOrder = NEO_RWGB;
} else if (strcmp(rgbOrder, "RWBG") == 0) {
returnOrder = NEO_RWBG;
} else if (strcmp(rgbOrder, "BWRG") == 0) {
returnOrder = NEO_BWRG;
} else if (strcmp(rgbOrder, "BWGR") == 0) {
returnOrder = NEO_BWGR;
} else if (strcmp(rgbOrder, "GRWB") == 0) {
returnOrder = NEO_GRWB;
} else if (strcmp(rgbOrder, "GBWR") == 0) {
returnOrder = NEO_GBWR;
} else if (strcmp(rgbOrder, "RGWB") == 0) {
returnOrder = NEO_RGWB;
} else if (strcmp(rgbOrder, "RBWG") == 0) {
returnOrder = NEO_RBWG;
} else if (strcmp(rgbOrder, "BRWG") == 0){
returnOrder = NEO_BRWG;
} else if (strcmp(rgbOrder, "BGWR") == 0) {
returnOrder = NEO_GRBW;
} else if (strcmp(rgbOrder, "GRBW") == 0) {
returnOrder = NEO_GRBW;
} else if (strcmp(rgbOrder, "GBWR") == 0) {
returnOrder = NEO_GBRW;
} else if (strcmp(rgbOrder, "RGBW") == 0) {
returnOrder = NEO_RGBW;
} else if (strcmp(rgbOrder, "RBGW") == 0) {
returnOrder = NEO_RBGW;
} else if (strcmp(rgbOrder, "BRGW") == 0) {
returnOrder = NEO_BRGW;
} else if (strcmp(rgbOrder, "BGRW") == 0) {
returnOrder = NEO_BGRW;
} else {
DBG_OUTPUT_PORT.print("invalid input!");
uint16_t check = checkRGBOrder(Config.RGBOrder);
if (check != 0) {
returnOrder = static_cast<neoPixelType>(check);
strcpy(rgbOrder, Config.RGBOrder);
} else {
returnOrder = static_cast<neoPixelType>(checkRGBOrder(RGBORDER));
strcpy(rgbOrder, RGBORDER);
}
}
DBG_OUTPUT_PORT.println("success!");
strcpy(Config.RGBOrder, rgbOrder);
return returnOrder;
}
// function to Initialize the strip
void initStrip(uint16_t _stripSize = Config.stripSize, uint8_t _num_segments = Config.segments, char _RGBOrder[5] = Config.RGBOrder, uint8_t _pin = Config.pin){
DBG_OUTPUT_PORT.println("Initializing strip!");
/*#if defined(USE_WS2812FX_DMA)
if (dma != NULL) {
delete(dma);
}
#endif*/
if (strip != NULL) {
strip->strip_off();
delay(10);
if(strip->isRunning()) strip->stop();
strip->resetSegments();
strip->resetSegmentRuntimes();
delete(strip);
Config.stripSize = _stripSize;
strcpy(Config.RGBOrder, _RGBOrder);
Config.pin = _pin;
}
if (ledstates != NULL) {
delete(ledstates);
}
ledstates = new uint8_t [_stripSize];
#if !defined(LED_TYPE_WS2811)
strip = new WS2812FX(_stripSize, _pin, checkRGBOrder(_RGBOrder) + NEO_KHZ800);
#else
strip = new WS2812FX(_stripSize, _pin, checkRGBOrder(_RGBOrder) + NEO_KHZ400);
#endif
// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel. Avoid connecting
// on a live circuit...if you must, connect GND first.
strip->init();
#if defined(USE_WS2812FX_DMA)
initDMA(_stripSize);
strip->setCustomShow(DMA_Show);
#endif
//parameters: index, start, stop, mode, color, speed, options
for (uint8_t _seg=0; _seg < Config.segments; _seg++) {
if (_seg != State.segment) { // Read actual segment last
(readSegmentStateFS(_seg)) ? DBG_OUTPUT_PORT.println("Segment state config FS read Success!") : DBG_OUTPUT_PORT.println("Segment state config FS read failure!");
memcpy(segState.colors[_seg], hexcolors_trans, sizeof(hexcolors_trans));
strip->setSegment(_seg, segState.start, segState.stop, segState.mode[_seg], segState.colors[_seg], convertSpeed(segState.speed[_seg]), segState.options);
}
}
//read actual segment last to set all vars correctly
(readSegmentStateFS(State.segment)) ? DBG_OUTPUT_PORT.println("Segment state config FS read Success!") : DBG_OUTPUT_PORT.println("Segment state config FS read failure!");
memcpy(segState.colors[State.segment], hexcolors_trans, sizeof(hexcolors_trans));
strip->setSegment(State.segment, segState.start, segState.stop , segState.mode[State.segment], hexcolors_trans, convertSpeed(segState.speed[State.segment]), segState.options);
fx_speed = segState.speed[State.segment];
fx_mode = segState.mode[State.segment];
brightness_trans = State.brightness;
prevsegment = State.segment;
strip->setCustomMode(0, F("Autoplay"), handleAuto);
strip->setCustomMode(1, F("Custom WS"), handleCustomWS);
strip->setCustomMode(9, F("Segment OFF"), handleSegmentOFF);
#if defined(CUSTOM_WS2812FX_ANIMATIONS)
strip->setCustomMode(2, F("TV"), handleTV);
strip->setCustomMode(3, F("E1.31"), handleE131);
strip->setCustomMode(4, F("Fire 2012"), handleFire2012);
strip->setCustomMode(5, F("Gradient"), handleGradient);
DBG_OUTPUT_PORT.print("Number of Segments: ");
DBG_OUTPUT_PORT.println(strip->getNumSegments());
if (e131 != NULL) { delete(e131); }
e131 = new ESPAsyncE131(END_UNIVERSE - START_UNIVERSE + 1);
float universe_leds = 170.0; // a universe has only 512 (0..511) channels: 3*170 or 4*128 <= 512
if (strstr(Config.RGBOrder, "W") != NULL) {
//universe_leds = 128.0;
}
float float_enduni = _stripSize/universe_leds;
uint8_t END_UNIVERSE = _stripSize/universe_leds;
if (float_enduni > END_UNIVERSE) {
END_UNIVERSE = END_UNIVERSE +1;
}
// if (e131.begin(E131_UNICAST)) // Listen via Unicast
if (e131->begin(E131_MULTICAST, START_UNIVERSE, END_UNIVERSE)) {// Listen via Multicast
DBG_OUTPUT_PORT.println(F("Listening for data..."));
} else {
DBG_OUTPUT_PORT.println(F("*** e131.begin failed ***"));
}
#endif
}
void getSegmentParams(uint8_t _seg) {
segState.start = strip->getSegment(_seg)->start;;
segState.stop = strip->getSegment(_seg)->stop;;
//segState.mode[_seg] = strip->getMode(_seg);
//segState.speed[_seg] = unconvertSpeed(strip->getSpeed(_seg));
//fx_mode = segState.mode[_seg];
//fx_speed = segState.speed[_seg];
main_color.white = ((segState.colors[_seg][0] >> 24) & 0xFF);
main_color.red = ((segState.colors[_seg][0] >> 16) & 0xFF);
main_color.green = ((segState.colors[_seg][0] >> 8) & 0xFF);
main_color.blue = ((segState.colors[_seg][0]) & 0xFF);
back_color.white = ((segState.colors[_seg][1] >> 24) & 0xFF);
back_color.red = ((segState.colors[_seg][1] >> 16) & 0xFF);
back_color.green = ((segState.colors[_seg][1] >> 8) & 0xFF);
back_color.blue = ((segState.colors[_seg][1]) & 0xFF);
xtra_color.white = ((segState.colors[_seg][2] >> 24) & 0xFF);
xtra_color.red = ((segState.colors[_seg][2] >> 16) & 0xFF);
xtra_color.green = ((segState.colors[_seg][2] >> 8) & 0xFF);
xtra_color.blue = ((segState.colors[_seg][2] >> 0) & 0xFF);
segState.options = strip->getOptions(_seg);
}
void setSegmentSize() {
strip->strip_off();
delay(10);
if(strip->isRunning()) strip->stop();
strip->resetSegmentRuntimes();
strip->setSegment(State.segment, segState.start, segState.stop , segState.mode[State.segment], hexcolors_trans, convertSpeed(segState.speed[State.segment]), segState.options);
}
uint8_t calculateColorTransitionSteps(uint8_t _seg) {
//compare all colors and calculate steps
int _trans_cnt_max = 0;
int _calculate_max[4] = {};
for (uint8_t i=0; i<3; i++){
for (uint8_t j=0; j<4; j++) {
_calculate_max[j] = ((strip->getColors(_seg)[i] >> ((3-j)*8)) & 0xFF) - ((hexcolors_trans[i] >> ((3-j)*8)) & 0xFF);
_calculate_max[j] = abs(_calculate_max[j]);
_trans_cnt_max = max(_trans_cnt_max, _calculate_max[j]);
}
}
return _trans_cnt_max;
}
uint8_t convertColorsFade(uint8_t _seg) {
if (Config.transEffect) {
if (trans_cnt > 1) {
//memcpy(segState.colors[_seg], strip->getColors(_seg), sizeof(segState.colors[_seg]));
DBG_OUTPUT_PORT.println("Color transistion aborted. Restarting...!");
trans_cnt = 1;
}
return calculateColorTransitionSteps(_seg);
} else {
return 0;
}
}
uint32_t scale_wrgb(uint32_t wrgb, uint8_t level) {
uint8_t w = (uint16_t)(((wrgb >> 24) & 0xFF) * level / 255);
uint8_t r = (uint16_t)(((wrgb >> 16) & 0xFF) * level / 255);
uint8_t g = (uint16_t)(((wrgb >> 8) & 0xFF) * level / 255);
uint8_t b = (uint16_t)(((wrgb) & 0xFF) * level / 255);
return (w << 24) | (r << 16) | (g << 8) | b;
}
uint32_t trans(uint32_t _newcolor, uint32_t _oldcolor, uint8_t _level, uint8_t _steps) {
if (_steps == 0) { _steps = 1; };
_level = (uint16_t)(_level * 255 / _steps);
_newcolor = scale_wrgb(_newcolor, _level);
_oldcolor = scale_wrgb(_oldcolor, 255-_level);
return _newcolor + _oldcolor;
}
+465 -459
View File
@@ -1,463 +1,469 @@
#include <pgmspace.h> #include <pgmspace.h>
#define edit_htm_gz_len 5489 #define edit_htm_gz_len 5563
static const char edit_htm_gz[] PROGMEM ={ static const char edit_htm_gz[] PROGMEM ={
0x1f, 0x8b, 0x08, 0x08, 0x10, 0x9c, 0x83, 0x5c, 0x04, 0x00, 0x65, 0x64, 0x1f, 0x8b, 0x08, 0x08, 0x79, 0x1c, 0x96, 0x5d, 0x04, 0x00, 0x65, 0x64,
0x69, 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x00, 0xed, 0x1c, 0x67, 0x7b, 0xf2, 0x69, 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x00, 0xed, 0x1d, 0x6b, 0x57, 0xea,
0x36, 0xf0, 0x7b, 0x7f, 0x85, 0xeb, 0x8e, 0x40, 0x99, 0x21, 0x24, 0x6f, 0x46, 0xf0, 0x7b, 0xcf, 0xe9, 0x7f, 0x48, 0xd3, 0x87, 0x50, 0x9e, 0xa2,
0x66, 0x5b, 0x76, 0x12, 0xa0, 0x84, 0x91, 0x84, 0xa4, 0xeb, 0x31, 0xb6, 0xd7, 0x2a, 0x6a, 0x5b, 0x40, 0x40, 0x45, 0x8a, 0x08, 0x2a, 0xda, 0xd7,
0x00, 0x27, 0xc6, 0x76, 0x6c, 0x13, 0x20, 0x69, 0xfa, 0xdb, 0x7b, 0x92, 0x09, 0xc9, 0x02, 0xd1, 0x90, 0xc4, 0x24, 0x08, 0x7a, 0x6b, 0x7f, 0x7b,
0xbc, 0x07, 0x38, 0xa3, 0xf3, 0x29, 0xef, 0x00, 0x4b, 0x77, 0xa7, 0xbb, 0x67, 0x1f, 0x79, 0x27, 0x10, 0xd4, 0x3e, 0x4f, 0xb9, 0xed, 0x25, 0xec,
0xd3, 0xe9, 0x74, 0x3a, 0x49, 0x3e, 0xfe, 0xbc, 0xda, 0xa9, 0x0c, 0x6e, 0xce, 0xcc, 0xce, 0xcc, 0xce, 0xce, 0xce, 0xce, 0xee, 0xe6, 0x1e, 0x7c,
0x2e, 0x6a, 0xcc, 0xd4, 0x98, 0x49, 0xdf, 0x7e, 0x76, 0x8c, 0xbf, 0x18, 0x76, 0xd4, 0xa9, 0xf5, 0x6f, 0xce, 0xeb, 0xdc, 0xc4, 0x9a, 0x2a, 0xdf,
0x89, 0x93, 0x27, 0x27, 0x2c, 0x92, 0xd9, 0x6f, 0x3f, 0x63, 0x98, 0xe3, 0x7e, 0xfa, 0xc9, 0x01, 0xfe, 0xe6, 0x14, 0x41, 0x1d, 0x1f, 0xf2, 0x48,
0x29, 0xe2, 0x04, 0xfc, 0x03, 0x7e, 0x1a, 0xa2, 0x21, 0xa1, 0x6f, 0xfb, 0xe5, 0xa1, 0x84, 0xe3, 0x0e, 0x26, 0x48, 0x90, 0xc8, 0x13, 0x3c, 0x5b,
0x17, 0x67, 0xf5, 0x7a, 0x9f, 0xa9, 0x09, 0xa2, 0xa1, 0x68, 0xc7, 0x39, 0xb2, 0xa5, 0xa0, 0x6f, 0x7b, 0xe7, 0x27, 0x8d, 0x46, 0x8f, 0xab, 0x4b,
0x52, 0x68, 0x02, 0xe8, 0xc6, 0x4a, 0x42, 0x8c, 0xb1, 0x52, 0xd1, 0x09, 0xb2, 0xa5, 0x19, 0x07, 0x05, 0x52, 0x68, 0x43, 0x98, 0xd6, 0x93, 0x82,
0x6b, 0xa0, 0xa5, 0x91, 0xe3, 0x75, 0x9d, 0x65, 0x66, 0x48, 0x10, 0xb9, 0x38, 0xeb, 0x49, 0x47, 0x87, 0xbc, 0x85, 0x16, 0x56, 0x41, 0x34, 0x4d,
0x13, 0x56, 0xe7, 0x35, 0x44, 0x89, 0x92, 0x4f, 0x96, 0x57, 0x64, 0x0c, 0x9e, 0x9b, 0x22, 0x49, 0x16, 0x0e, 0x79, 0x53, 0x34, 0x10, 0xa3, 0x4b,
0xd3, 0x46, 0xf2, 0x9c, 0x79, 0x86, 0x42, 0xfa, 0x79, 0xca, 0x88, 0xb2, 0x3e, 0x79, 0x51, 0x53, 0x31, 0x50, 0x1b, 0xa9, 0x33, 0xee, 0x23, 0x94,
0x80, 0x96, 0x87, 0xcc, 0x4e, 0x3e, 0x7f, 0x64, 0x97, 0xaa, 0x8a, 0x2e, 0xb2, 0xcf, 0x73, 0x4e, 0x56, 0x25, 0xb4, 0x28, 0x73, 0x5b, 0xc5, 0xe2,
0x1a, 0xa2, 0x22, 0x1f, 0x32, 0xdc, 0x48, 0x57, 0xa4, 0xb9, 0x81, 0x9c, 0xbe, 0x5b, 0xac, 0x6b, 0xa6, 0x6c, 0xc9, 0x9a, 0x5a, 0xe6, 0x84, 0xa1,
0x3a, 0x09, 0x8d, 0x8d, 0x43, 0x66, 0x57, 0x5d, 0x3a, 0x45, 0x23, 0x45, 0xa9, 0x29, 0x33, 0x0b, 0x79, 0x2a, 0x15, 0x34, 0xb2, 0xca, 0xdc, 0x07,
0x13, 0x90, 0x76, 0xc8, 0x6c, 0xab, 0x4b, 0x06, 0xc0, 0x45, 0x81, 0xf9, 0x7d, 0xe1, 0x29, 0x1b, 0x6a, 0x86, 0x84, 0x8c, 0x32, 0xb7, 0xa9, 0x2f,
0xa2, 0x58, 0x2c, 0xba, 0xea, 0x39, 0xfe, 0x7e, 0xa2, 0x29, 0x73, 0x59, 0x38, 0x40, 0x90, 0x25, 0xee, 0xf3, 0xed, 0xed, 0x6d, 0x2f, 0x80, 0x20,
0xc8, 0xf0, 0x8a, 0xa4, 0x00, 0xe4, 0x17, 0xf5, 0x5d, 0xfc, 0xc7, 0x01, 0xde, 0x8f, 0x0d, 0x6d, 0xa6, 0x4a, 0x39, 0x51, 0x53, 0x34, 0x00, 0xfd,
0x11, 0x44, 0x5d, 0x95, 0xb8, 0xd5, 0x21, 0x23, 0x2b, 0x32, 0x72, 0x53, 0xbc, 0xf1, 0x01, 0xff, 0xf1, 0xc0, 0x48, 0xb2, 0xa9, 0x2b, 0xc2, 0x53,
0x5e, 0x66, 0xf4, 0x29, 0x27, 0x28, 0x8b, 0x43, 0x26, 0x0f, 0x7f, 0xb6, 0x99, 0x53, 0x35, 0x15, 0xf9, 0x88, 0x2f, 0x72, 0xe6, 0x44, 0x90, 0xb4,
0xf3, 0xd0, 0x84, 0x36, 0x19, 0x71, 0x09, 0x26, 0x9f, 0x36, 0xff, 0x66, 0x79, 0x99, 0x2b, 0xc2, 0x9f, 0xcd, 0x22, 0xb4, 0x62, 0x8c, 0x87, 0x42,
0x8b, 0x4c, 0xd2, 0xc1, 0x18, 0x83, 0x98, 0x19, 0x5d, 0x7c, 0x42, 0xc0, 0x8a, 0x2b, 0x66, 0xd9, 0x7f, 0xf9, 0x6d, 0x2e, 0xed, 0x41, 0x19, 0x81,
0x4e, 0xc1, 0x64, 0xd2, 0xa9, 0x18, 0x73, 0x33, 0x51, 0x82, 0x56, 0x74, 0xb8, 0x39, 0x53, 0x7e, 0x46, 0xc0, 0x52, 0xc9, 0xe6, 0xd4, 0xad, 0x19,
0x4e, 0xd6, 0x33, 0x3a, 0xd2, 0xc4, 0xb1, 0x0f, 0x60, 0x81, 0xc4, 0xc9, 0x09, 0x53, 0x59, 0x81, 0x86, 0x4c, 0x41, 0x35, 0x73, 0x26, 0x32, 0xe4,
0xd4, 0x38, 0x1c, 0x29, 0x92, 0x60, 0xd5, 0xbc, 0x84, 0x69, 0x70, 0x2e, 0x51, 0x10, 0x62, 0x8e, 0xe4, 0xf1, 0xc4, 0x2a, 0x0f, 0x35, 0x45, 0x72,
0xb9, 0x94, 0x28, 0x89, 0x3a, 0xb4, 0x89, 0x3b, 0xc3, 0xcf, 0xbf, 0xa1, 0xaa, 0x5e, 0x22, 0xb5, 0x39, 0x53, 0xbc, 0x0a, 0x55, 0x64, 0x13, 0x1a,
0xa8, 0xc0, 0xb8, 0x57, 0x79, 0x9e, 0x82, 0x19, 0xa7, 0x4d, 0x44, 0xd9, 0xc6, 0x5d, 0x13, 0x12, 0xc3, 0xd2, 0x74, 0xe0, 0x3f, 0xa0, 0x48, 0x7f,
0x53, 0xa4, 0x72, 0x82, 0x20, 0xca, 0x13, 0x28, 0x5b, 0xc7, 0x01, 0x34, 0xc9, 0x54, 0x30, 0xc6, 0xb2, 0xea, 0x2f, 0xd3, 0x05, 0x49, 0x92, 0xd5,
0x0a, 0x1c, 0x04, 0x3b, 0x4c, 0x43, 0x12, 0x67, 0x88, 0x8f, 0xc8, 0xd5, 0x31, 0x14, 0x2e, 0x67, 0x04, 0x9a, 0xc6, 0x8c, 0x84, 0xbb, 0xd0, 0x40,
0x84, 0x28, 0x67, 0x16, 0xa2, 0x60, 0x4c, 0x0f, 0x99, 0xbd, 0xbc, 0x5b, 0x8a, 0x60, 0xc9, 0x8f, 0xc8, 0xdb, 0x8e, 0xac, 0xe6, 0xe6, 0xb2, 0x64,
0x23, 0xfc, 0x5c, 0xd3, 0xa1, 0x33, 0x00, 0x59, 0x04, 0xb2, 0xda, 0xda, 0x4d, 0xca, 0xdc, 0x4e, 0xd1, 0xa7, 0x1e, 0x71, 0x66, 0x98, 0xd0, 0x3b,
0xd6, 0x74, 0x95, 0x93, 0x5d, 0xed, 0xd1, 0x6e, 0xa4, 0xdd, 0x1c, 0xec, 0x80, 0x2e, 0x03, 0x65, 0x63, 0x45, 0x93, 0xa6, 0x2e, 0xa8, 0xde, 0x46,
0x43, 0x51, 0x96, 0x44, 0x19, 0x65, 0x46, 0x92, 0xc2, 0xdf, 0x87, 0xc8, 0x69, 0xd7, 0xb2, 0xbe, 0x0f, 0xf7, 0xab, 0xac, 0x2a, 0xb2, 0x8a, 0x72,
0xb5, 0xa7, 0x2e, 0x37, 0x48, 0x76, 0x38, 0x55, 0x1e, 0x91, 0xc6, 0x3c, 0x43, 0x45, 0x13, 0xef, 0xa3, 0x24, 0xdc, 0xd1, 0x17, 0x2b, 0x65, 0x2c,
0xbb, 0x2c, 0xc7, 0x6c, 0x6c, 0x3d, 0x86, 0xc9, 0xa6, 0xcd, 0x5e, 0xad, 0x4f, 0xb4, 0x47, 0x64, 0x70, 0x1f, 0x3d, 0x16, 0xc5, 0x1a, 0x5c, 0x81,
0x56, 0xb3, 0x30, 0x6c, 0x34, 0x5d, 0xcf, 0x18, 0x30, 0x32, 0x1e, 0x45, 0xc2, 0x98, 0x75, 0x78, 0xac, 0xd7, 0xeb, 0x0e, 0x8a, 0x8b, 0x68, 0x9a,
0xb4, 0x80, 0x5e, 0x4c, 0xfb, 0x4a, 0x1c, 0xad, 0x3a, 0x1c, 0x47, 0x74, 0x39, 0x0b, 0x86, 0xce, 0xa3, 0x8c, 0xe6, 0xd0, 0xb3, 0x59, 0x7f, 0x09,
0xd8, 0xc6, 0xee, 0x7f, 0xf9, 0x2c, 0xb4, 0x51, 0x51, 0x56, 0xe7, 0x06, 0x51, 0x71, 0x88, 0xef, 0xd5, 0x5d, 0x18, 0x36, 0x0a, 0x57, 0xc8, 0xe8,
0xf3, 0x1c, 0x6b, 0xb0, 0x29, 0x2a, 0xc7, 0x8b, 0xc6, 0x0a, 0x9a, 0xdb, 0xa6, 0x65, 0x55, 0x9f, 0x59, 0xdc, 0xc7, 0x84, 0x23, 0x52, 0xd3, 0x05,
0x40, 0xf4, 0xd9, 0x63, 0xc6, 0x98, 0x0f, 0x6d, 0xc6, 0x49, 0xcc, 0x36, 0x51, 0xb6, 0x9e, 0xa0, 0xd1, 0xd5, 0x94, 0x3f, 0xfa, 0x0d, 0x1d, 0x33,
0x1e, 0x92, 0x57, 0x48, 0x13, 0x38, 0x99, 0x4b, 0x33, 0x25, 0x4d, 0xe4, 0x64, 0x4c, 0x05, 0x85, 0xdb, 0xc4, 0x43, 0xf7, 0x0a, 0x19, 0x92, 0xa0,
0x40, 0xe2, 0x7e, 0x88, 0xf1, 0x67, 0x66, 0xca, 0x53, 0x66, 0x0e, 0x85, 0x0a, 0x59, 0xae, 0x62, 0xc8, 0x02, 0x48, 0xdf, 0x8b, 0x1a, 0x1f, 0xb9,
0x50, 0x21, 0x21, 0xde, 0xf0, 0x1b, 0x32, 0x0c, 0x8c, 0xd1, 0xbd, 0x68, 0xa9, 0xf6, 0x9c, 0x9b, 0x41, 0x29, 0xd4, 0x28, 0x48, 0xb4, 0x42, 0x86,
0xac, 0x03, 0x71, 0x55, 0xc5, 0xd2, 0x43, 0x84, 0x49, 0xe5, 0xf3, 0xe3, 0x0e, 0x83, 0x67, 0x78, 0x2f, 0x5b, 0x4b, 0x61, 0x3c, 0x75, 0x49, 0x75,
0x18, 0x26, 0x1a, 0x49, 0xd1, 0x34, 0x04, 0x87, 0x2e, 0x36, 0x92, 0x8c, 0x12, 0x67, 0x6c, 0xc5, 0xe2, 0x28, 0x99, 0x01, 0xc7, 0x93, 0xb5, 0x8d,
0x80, 0x78, 0x45, 0xe3, 0xa8, 0x96, 0xc1, 0x98, 0x90, 0x26, 0x89, 0x1b, 0xca, 0x25, 0x83, 0xcd, 0x27, 0x27, 0x21, 0x51, 0x33, 0x04, 0xaa, 0x76,
0xf9, 0xa3, 0xfd, 0x94, 0x02, 0xff, 0x3c, 0x42, 0x12, 0x7c, 0xe3, 0x21, 0xb0, 0x33, 0x64, 0x28, 0x72, 0x12, 0x46, 0x69, 0xe7, 0x65, 0xc0, 0xbd,
0x1f, 0x34, 0x03, 0xf2, 0xa7, 0x00, 0x9e, 0x26, 0x16, 0xb5, 0xdf, 0x09, 0x0f, 0x91, 0x02, 0xdf, 0xc4, 0x43, 0x84, 0x0d, 0x84, 0xfc, 0x29, 0x81,
0x15, 0xff, 0x88, 0x89, 0xa5, 0x2e, 0xc2, 0x46, 0x3a, 0xac, 0xf0, 0xf0, 0x77, 0x4a, 0x4a, 0xf1, 0x77, 0x42, 0x29, 0x34, 0xae, 0x92, 0xea, 0x8f,
0x70, 0x84, 0xc6, 0x8a, 0x86, 0x98, 0xe7, 0x37, 0xea, 0x8d, 0xf0, 0x76, 0xb0, 0x93, 0x8d, 0x2a, 0x2c, 0x97, 0x87, 0x68, 0xa4, 0x19, 0x88, 0xfb,
0x08, 0xcc, 0x70, 0x23, 0x09, 0x09, 0xb6, 0xc8, 0x41, 0x72, 0x02, 0x1a, 0xf8, 0x06, 0x3d, 0x12, 0x1e, 0xcb, 0xc0, 0x93, 0x30, 0x54, 0x90, 0x64,
0x73, 0x73, 0xc9, 0x08, 0xb1, 0xcf, 0xec, 0x5e, 0xac, 0x36, 0xf8, 0x29, 0x8b, 0x1f, 0x45, 0x52, 0x42, 0x23, 0x61, 0xa6, 0x58, 0x51, 0x06, 0x9c,
0xe2, 0xef, 0x91, 0x70, 0x28, 0x2b, 0x46, 0xc2, 0x6e, 0x30, 0x19, 0xa9, 0xdf, 0x49, 0xda, 0x90, 0x38, 0x41, 0xe2, 0x3d, 0x92, 0xca, 0xaa, 0x66,
0x16, 0xe2, 0x41, 0x3e, 0x52, 0x2f, 0x6e, 0x7f, 0x32, 0xd7, 0xa4, 0x04, 0xa5, 0x9c, 0x56, 0xd3, 0xf1, 0x3a, 0x22, 0x4e, 0x67, 0x35, 0xf1, 0xf5,
0x2b, 0x70, 0x06, 0x77, 0x28, 0xce, 0xb8, 0x09, 0xca, 0xa9, 0xf2, 0xe4, 0x94, 0xe4, 0xf5, 0x41, 0x33, 0x43, 0x49, 0xf1, 0x92, 0x60, 0x09, 0x65,
0x68, 0xc4, 0xe9, 0x68, 0xaf, 0x98, 0x16, 0xaf, 0xca, 0x9d, 0xde, 0x22, 0x79, 0x2a, 0x8c, 0x51, 0x41, 0x57, 0xc7, 0xfb, 0x43, 0xc1, 0x44, 0x3b,
0xdf, 0x6c, 0x4c, 0x94, 0x12, 0x7c, 0x7e, 0xe8, 0x5f, 0x4e, 0x6b, 0x97, 0xdb, 0x59, 0xf9, 0xaa, 0xda, 0xb9, 0x98, 0x17, 0x5b, 0xcd, 0xb1, 0x56,
0x13, 0xf8, 0x55, 0xc6, 0x8f, 0x95, 0x49, 0xa5, 0x74, 0x83, 0x7f, 0xd4, 0x81, 0xcf, 0x0f, 0xbd, 0xcb, 0x49, 0xfd, 0x72, 0x0c, 0x4f, 0x55, 0xfc,
0x3b, 0x68, 0x71, 0x89, 0x7f, 0x34, 0x86, 0xbd, 0xfa, 0xf5, 0x69, 0x6f, 0xb3, 0x36, 0xae, 0x55, 0x6e, 0xf0, 0x43, 0xa3, 0x83, 0xe6, 0x97, 0xf8,
0x30, 0x2a, 0xdc, 0xe6, 0x85, 0x42, 0x7d, 0x75, 0xdb, 0x2d, 0x97, 0x6f, 0xa1, 0x39, 0xb8, 0x68, 0x5c, 0x1f, 0x5f, 0xf4, 0x87, 0xa5, 0xdb, 0xa2,
0x1b, 0x07, 0xe2, 0x6d, 0xbf, 0x7c, 0x3e, 0xba, 0xae, 0xcb, 0xb7, 0x57, 0x54, 0x6a, 0x3c, 0xdd, 0x76, 0xab, 0xd5, 0xdb, 0xe6, 0x9e, 0x7c, 0xdb,
0xe7, 0xd2, 0xcd, 0x75, 0x6f, 0x97, 0xe7, 0x25, 0xe9, 0x02, 0x23, 0xa8, 0xab, 0x9e, 0x0e, 0xaf, 0x1b, 0xea, 0xed, 0xd5, 0xa9, 0x72, 0x73, 0x7d,
0xcb, 0xf3, 0x5e, 0xad, 0x7e, 0x89, 0x7e, 0xd0, 0x74, 0xa9, 0xbd, 0x3d, 0xf1, 0x41, 0x14, 0x15, 0xe5, 0x1c, 0x23, 0xe8, 0x8b, 0xd3, 0x8b, 0x7a,
0xcf, 0xe7, 0x4b, 0xdd, 0x49, 0x03, 0x5c, 0xf4, 0x8a, 0x93, 0xea, 0xf5, 0xe3, 0x12, 0xfd, 0x60, 0x98, 0x4a, 0x7b, 0x73, 0x56, 0x2c, 0x56, 0xba,
0x4e, 0x33, 0x55, 0x91, 0xce, 0xce, 0x9a, 0xdd, 0xe6, 0xea, 0xe1, 0xf2, 0xe3, 0x26, 0xb8, 0xf7, 0x27, 0x41, 0x69, 0x34, 0x3a, 0xad, 0x4c, 0x4d,
0xaa, 0xfb, 0x38, 0xa8, 0xd5, 0x76, 0xaa, 0xb3, 0xd2, 0xb4, 0xb5, 0x28, 0x39, 0x39, 0x69, 0x75, 0x5b, 0x4f, 0x0f, 0x97, 0x57, 0xdd, 0xc7, 0x7e,
0x4d, 0x2f, 0xf7, 0xbb, 0xb7, 0xca, 0x69, 0xb1, 0x54, 0xe8, 0x16, 0x26, 0xbd, 0xbe, 0x75, 0x34, 0xad, 0x4c, 0xce, 0xe6, 0x95, 0xc9, 0xe5, 0x6e,
0xed, 0x7e, 0x9d, 0xe3, 0x51, 0xb1, 0x5d, 0x31, 0xce, 0xf7, 0xfb, 0x17, 0xf7, 0x56, 0x3b, 0xde, 0xae, 0x94, 0xba, 0xa5, 0x71, 0xbb, 0xd7, 0x10,
0xe5, 0xfa, 0xa2, 0x74, 0xdf, 0x9b, 0x8b, 0xa7, 0x4d, 0xb5, 0xb4, 0xa7, 0x44, 0xb4, 0xdd, 0xae, 0x59, 0xa7, 0xbb, 0xbd, 0xf3, 0x6a, 0x63, 0x5e,
0xf7, 0x7e, 0xc8, 0xb5, 0xe6, 0x9f, 0x9e, 0x1a, 0xbb, 0xe2, 0x76, 0xf1, 0xb9, 0xbf, 0x98, 0xc9, 0xc7, 0x2d, 0xbd, 0xb2, 0x63, 0x5e, 0xfc, 0x50,
0x9e, 0x37, 0xb8, 0xcb, 0x87, 0x5e, 0x63, 0xda, 0x18, 0xca, 0xf3, 0x83, 0x38, 0x9b, 0x7d, 0xf3, 0xdc, 0xfc, 0x20, 0x6f, 0x6e, 0xdf, 0x8b, 0x96,
0x4e, 0xee, 0xc2, 0xf8, 0xd4, 0x7e, 0xd2, 0xdb, 0xe2, 0xbd, 0xf4, 0x58, 0x70, 0xf9, 0x70, 0xd1, 0x9c, 0x34, 0x07, 0xea, 0x6c, 0xaf, 0x53, 0x38,
0x4f, 0x1d, 0x18, 0x85, 0xfb, 0xeb, 0x41, 0xf5, 0x71, 0x75, 0xa6, 0x95, 0xb7, 0xbe, 0x69, 0x3f, 0x9b, 0x6d, 0xf9, 0x5e, 0x79, 0x6c, 0x64, 0xf6,
0xf4, 0x52, 0x9e, 0x6b, 0xf6, 0x7a, 0xe2, 0xf6, 0x20, 0x5f, 0xc9, 0x4d, 0xac, 0xd2, 0xfd, 0x75, 0xff, 0xe8, 0xf1, 0xe9, 0xc4, 0xa8, 0x98, 0x95,
0xcf, 0x8b, 0xad, 0xcb, 0x91, 0xb1, 0x9b, 0xdb, 0xd7, 0x7e, 0x50, 0xaf, 0xa2, 0xd0, 0xba, 0xb8, 0x90, 0x37, 0xfb, 0xc5, 0x5a, 0x61, 0x72, 0xba,
0xaf, 0x24, 0x75, 0xbf, 0xd7, 0xd7, 0x0e, 0xce, 0x8b, 0xf9, 0x51, 0x71, 0x7d, 0x76, 0x39, 0xb4, 0x3e, 0x14, 0x76, 0x8d, 0x1f, 0xf4, 0xeb, 0x2b,
0x7f, 0xbc, 0xac, 0x73, 0x83, 0xee, 0x41, 0x6a, 0x6c, 0xec, 0xd7, 0x6e, 0x45, 0xdf, 0xbd, 0xe8, 0x19, 0x7b, 0xa7, 0xdb, 0xc5, 0xe1, 0xf6, 0xee,
0xf7, 0xda, 0xe7, 0x37, 0xa3, 0x7c, 0xe7, 0x3e, 0x25, 0xc8, 0x37, 0x0d, 0x68, 0xd1, 0x10, 0xfa, 0xdd, 0xbd, 0xcc, 0xc8, 0xda, 0xad, 0xdf, 0xee,
0x75, 0x76, 0x31, 0x19, 0x2e, 0x9a, 0x67, 0xa5, 0xc7, 0xd6, 0x72, 0xff, 0xb4, 0x4f, 0x6f, 0x86, 0xc5, 0xce, 0x7d, 0x46, 0x52, 0x6f, 0x9a, 0xfa,
0xf1, 0x66, 0xc8, 0xef, 0x36, 0x84, 0x76, 0xa9, 0x7b, 0x3e, 0xe9, 0xd6, 0xf4, 0x7c, 0x3c, 0x98, 0xb7, 0x4e, 0x2a, 0x8f, 0x67, 0x8b, 0xdd, 0xc7,
0xee, 0xd5, 0xbb, 0xde, 0x60, 0xba, 0xb3, 0x37, 0xe8, 0x17, 0x2e, 0x53, 0x9b, 0x81, 0xf8, 0xa1, 0x29, 0xb5, 0x2b, 0xdd, 0xd3, 0x71, 0xb7, 0x7e,
0xd5, 0xeb, 0xeb, 0x5c, 0x75, 0xfb, 0xd3, 0xf5, 0xfc, 0x66, 0x32, 0xdb, 0xaf, 0xdf, 0x5d, 0xf4, 0x27, 0x5b, 0x3b, 0xfd, 0x5e, 0xe9, 0x32, 0x73,
0x57, 0x17, 0xe7, 0xab, 0x9b, 0x6d, 0x59, 0xbd, 0xd5, 0x6f, 0x9b, 0x9d, 0x74, 0x7d, 0x5d, 0x38, 0xda, 0xfc, 0xe6, 0x7a, 0x76, 0x33, 0x9e, 0xee,
0xe5, 0xd9, 0xac, 0x73, 0xb5, 0x7d, 0x96, 0x9b, 0x16, 0x53, 0x9d, 0xbd, 0xea, 0xf3, 0xd3, 0xa7, 0x9b, 0x4d, 0x55, 0xbf, 0x35, 0x6f, 0x5b, 0x9d,
0xc7, 0xda, 0x64, 0xb7, 0x51, 0xb9, 0x2d, 0xab, 0x93, 0x59, 0x69, 0x6f, 0xc5, 0xc9, 0xb4, 0x73, 0xb5, 0x79, 0x52, 0x98, 0x6c, 0x67, 0x3a, 0x3b,
0x3a, 0xdc, 0x5f, 0x9c, 0x36, 0x2f, 0x4f, 0xab, 0xbd, 0xf2, 0xb0, 0x7b, 0x8f, 0xf5, 0xf1, 0x87, 0x66, 0xed, 0xb6, 0xaa, 0x8f, 0xa7, 0x95, 0x9d,
0x23, 0xf2, 0xdd, 0xa2, 0x26, 0xf1, 0x3b, 0x83, 0x71, 0xfe, 0xaa, 0xad, 0xc9, 0x60, 0x77, 0x7e, 0xdc, 0xba, 0x3c, 0x3e, 0xba, 0xa8, 0x0e, 0xba,
0xef, 0x57, 0x4f, 0xcb, 0xfd, 0xfd, 0xbd, 0x62, 0xbd, 0x70, 0x53, 0xd7, 0x37, 0xb2, 0xd8, 0xdd, 0x36, 0x14, 0x71, 0xab, 0x3f, 0x2a, 0x5e, 0xb5,
0xd5, 0xbb, 0xc9, 0xe5, 0xcd, 0x5d, 0x73, 0x98, 0x2b, 0x3d, 0xed, 0x4c, 0xcd, 0xdd, 0xa3, 0xe3, 0x6a, 0x6f, 0x77, 0x67, 0xbb, 0x51, 0xba, 0x69,
0x74, 0xa1, 0x2b, 0x14, 0x10, 0x2a, 0x9f, 0x2e, 0x66, 0x42, 0xe3, 0x7a, 0x98, 0xfa, 0xdd, 0xf8, 0xf2, 0xe6, 0xae, 0x35, 0x28, 0x54, 0x9e, 0xb7,
0x78, 0xca, 0x4f, 0xca, 0x8d, 0xfe, 0xfd, 0xed, 0xb0, 0x33, 0x54, 0xa6, 0xc6, 0xa6, 0xd4, 0x95, 0x4a, 0x08, 0x55, 0x8f, 0xe7, 0x53, 0xa9, 0x79,
0x7c, 0x6d, 0x88, 0x46, 0x3d, 0xa5, 0xcb, 0x97, 0x26, 0x77, 0x0f, 0x10, 0x3d, 0x38, 0x16, 0xc7, 0xd5, 0x66, 0xef, 0xfe, 0x76, 0xd0, 0x19, 0x68,
0x36, 0xfd, 0x70, 0x93, 0x2a, 0x5d, 0xad, 0xe6, 0x3b, 0xb7, 0x3b, 0x7a, 0x13, 0xb1, 0x3e, 0x40, 0xc3, 0x0b, 0xad, 0x2b, 0x56, 0xc6, 0x77, 0x0f,
0xa9, 0xf9, 0x30, 0x6e, 0x2a, 0x8d, 0xb6, 0x8e, 0x16, 0x65, 0x54, 0x3b, 0x10, 0x88, 0xfd, 0x70, 0x93, 0xa9, 0x5c, 0x3d, 0xcd, 0xb6, 0x6e, 0xb7,
0xeb, 0x5c, 0x4c, 0xba, 0xcb, 0xe5, 0xc5, 0xf9, 0xd9, 0x1d, 0xdf, 0x38, 0xcc, 0x4a, 0xeb, 0x61, 0xd4, 0xd2, 0x9a, 0x6d, 0x13, 0xcd, 0xab, 0xa8,
0xdd, 0x7b, 0x30, 0x5a, 0xb9, 0x7c, 0x49, 0x28, 0x55, 0x9f, 0x9a, 0x0d, 0x7e, 0xd2, 0x39, 0x1f, 0x77, 0x17, 0x8b, 0xf3, 0xd3, 0x93, 0x3b, 0xb1,
0x79, 0x3e, 0xaf, 0xa6, 0x0a, 0x46, 0xab, 0xf9, 0xa9, 0xbb, 0x5f, 0x9d, 0x79, 0xbc, 0xf3, 0x60, 0x9d, 0x15, 0x8a, 0x15, 0xa9, 0x72, 0xf4, 0xdc,
0x9e, 0x9e, 0x8e, 0x3a, 0xe5, 0xeb, 0x54, 0xb3, 0xf6, 0xc4, 0x9f, 0xb6, 0x6a, 0xaa, 0xb3, 0xd9, 0x51, 0xa6, 0x64, 0x9d, 0xb5, 0xbe, 0xe9, 0xee,
0xe6, 0x37, 0xfc, 0x7e, 0xa1, 0x7d, 0x5f, 0xbb, 0x44, 0xf7, 0x2d, 0x71, 0x1e, 0x4d, 0x8e, 0x8f, 0x87, 0x9d, 0xea, 0x75, 0xa6, 0x55, 0x7f, 0x16,
0x31, 0x7f, 0xbc, 0x3a, 0x4d, 0x4d, 0xe6, 0xdd, 0x72, 0xf7, 0xa9, 0xd3, 0x8f, 0xcf, 0x66, 0x37, 0xe2, 0x6e, 0xa9, 0x7d, 0x5f, 0xbf, 0x44, 0xf7,
0x28, 0x0e, 0x85, 0xd2, 0x68, 0xbf, 0xd6, 0xe1, 0x7b, 0xfc, 0x43, 0xf7, 0x67, 0xf2, 0x7c, 0xf6, 0x78, 0x75, 0x9c, 0x19, 0xcf, 0xba, 0xd5, 0xee,
0xb1, 0x7a, 0x7f, 0x53, 0x10, 0x2b, 0xad, 0xf9, 0xb2, 0x56, 0x39, 0x2f, 0x73, 0xa7, 0xb9, 0x3d, 0x90, 0x2a, 0xc3, 0xdd, 0x7a, 0x47, 0xbc, 0x10,
0xee, 0x9c, 0x2b, 0xa3, 0xf6, 0x50, 0x99, 0x1b, 0x0f, 0x8d, 0x49, 0x95, 0x1f, 0xba, 0x8f, 0x47, 0xf7, 0x37, 0x25, 0xb9, 0x76, 0x36, 0x5b, 0xd4,
0x2b, 0x0c, 0x3e, 0x5d, 0x3e, 0xb4, 0x9a, 0x0b, 0xe3, 0xa0, 0xd9, 0x5b, 0x6b, 0xa7, 0xdb, 0x5b, 0xa7, 0xda, 0xb0, 0x3d, 0xd0, 0x66, 0xd6, 0x43,
0xcd, 0x97, 0xcd, 0xab, 0xf2, 0xea, 0xe1, 0x6a, 0x38, 0x7c, 0x38, 0x53, 0x73, 0x7c, 0x24, 0x94, 0xfa, 0xdf, 0x5c, 0x3e, 0x9c, 0xb5, 0xe6, 0xd6,
0x2a, 0x95, 0xcb, 0x4a, 0xe9, 0x61, 0x7a, 0xd9, 0x11, 0x95, 0xc1, 0x75, 0x5e, 0xeb, 0xe2, 0x69, 0xb6, 0x68, 0x5d, 0x55, 0x9f, 0x1e, 0xae, 0x06,
0xe5, 0x53, 0xa3, 0x38, 0xe8, 0xd6, 0x3a, 0xd5, 0x7c, 0xe9, 0x62, 0x55, 0x83, 0x87, 0x13, 0xad, 0x56, 0xbb, 0xac, 0x55, 0x1e, 0x26, 0x97, 0x1d,
0xc8, 0x7d, 0x6a, 0x14, 0x86, 0xea, 0x7c, 0xfb, 0xbc, 0x98, 0x92, 0x96, 0x59, 0xeb, 0x5f, 0xd7, 0xbe, 0x69, 0x6e, 0xf7, 0xbb, 0xf5, 0xce, 0x51,
0xa8, 0x5b, 0x1c, 0x0c, 0xcb, 0xa3, 0xb3, 0x41, 0x55, 0x55, 0xae, 0x90, 0xb1, 0x72, 0xfe, 0x54, 0x2a, 0x7c, 0xd3, 0x2c, 0x0d, 0xf4, 0xd9, 0xe6,
0x04, 0x96, 0x51, 0xbe, 0xaa, 0x8f, 0x16, 0xf3, 0x5d, 0xa5, 0xdd, 0x3e, 0xe9, 0x76, 0x46, 0x59, 0xa0, 0xee, 0x76, 0x7f, 0x50, 0x1d, 0x9e, 0xf4,
0xbf, 0x2c, 0x4f, 0x95, 0xe1, 0x6a, 0xd7, 0x98, 0x09, 0x3d, 0xbe, 0xbd, 0x8f, 0x74, 0xed, 0x0a, 0x29, 0x60, 0x19, 0xd5, 0xab, 0xc6, 0x70, 0x3e,
0x58, 0xcd, 0x2e, 0x0a, 0x9d, 0x56, 0x97, 0x6b, 0xdd, 0x2d, 0x0f, 0x72, 0xfb, 0xa0, 0xb5, 0xdb, 0xa7, 0x97, 0xd5, 0x89, 0x36, 0x78, 0xfa, 0x60,
0x8f, 0x72, 0x59, 0xd9, 0xbb, 0xda, 0x69, 0xee, 0x89, 0x4f, 0xa5, 0xc1, 0x4d, 0xa5, 0x0b, 0xb1, 0x3d, 0x7f, 0x9a, 0x9e, 0x97, 0x3a, 0x67, 0x5d,
0xac, 0x2f, 0xb7, 0xb9, 0x7c, 0xf5, 0xe1, 0xd3, 0x18, 0x69, 0x67, 0xca, 0xe1, 0xec, 0x6e, 0xb1, 0x57, 0x78, 0x54, 0xab, 0xda, 0xce, 0xd5, 0x56,
0xf4, 0x7c, 0xaa, 0x6d, 0xab, 0xf9, 0xed, 0x27, 0x4d, 0x7a, 0x2a, 0x1e, 0x6b, 0x47, 0x7e, 0xae, 0xf4, 0xa7, 0x3d, 0xb5, 0x2d, 0x14, 0x8f, 0x1e,
0x68, 0xb7, 0xf5, 0x62, 0x07, 0xba, 0xe0, 0xfc, 0x7e, 0x58, 0xd8, 0x79, 0xbe, 0x19, 0x21, 0xe3, 0x44, 0x9b, 0x9c, 0x4e, 0x8c, 0x4d, 0xbd, 0xb8,
0xbc, 0xea, 0x3e, 0xdd, 0xa8, 0xa9, 0xc5, 0xe8, 0xa6, 0x71, 0x95, 0x6b, 0xf9, 0x6c, 0x28, 0xcf, 0xdb, 0x7b, 0xc6, 0x6d, 0x63, 0xbb, 0x03, 0x5d,
0xaa, 0xc3, 0xe6, 0xdd, 0x23, 0x0c, 0xe6, 0x7d, 0x43, 0x3f, 0x6b, 0x56, 0x70, 0x7a, 0x3f, 0x28, 0x6d, 0x3d, 0x5e, 0x75, 0x9f, 0x6f, 0xf4, 0xcc,
0xb4, 0xf6, 0x0f, 0xa5, 0x9b, 0xfa, 0xf2, 0xae, 0xd0, 0x68, 0xf6, 0x77, 0x7c, 0x78, 0xd3, 0xbc, 0x2a, 0xb4, 0xf4, 0x41, 0xeb, 0xee, 0x11, 0x06,
0x6f, 0xaf, 0x97, 0x93, 0x22, 0x5a, 0x34, 0xf5, 0xf3, 0x31, 0xd7, 0x68, 0xf4, 0xae, 0x65, 0x9e, 0xb4, 0x6a, 0x46, 0xfb, 0x87, 0xca, 0x4d, 0x63,
0x9f, 0xdd, 0xec, 0x36, 0x87, 0x0f, 0x17, 0x4f, 0xfb, 0xad, 0x72, 0xf9, 0x71, 0x57, 0x6a, 0xb6, 0x7a, 0x1f, 0x6e, 0xaf, 0x17, 0xe3, 0x6d, 0x34,
0x6e, 0x2f, 0xb5, 0xaa, 0x3e, 0x5e, 0x5d, 0x7c, 0x3a, 0x80, 0x6f, 0x35, 0x6f, 0x99, 0xa7, 0x23, 0xa1, 0xd9, 0x3e, 0xb9, 0xf9, 0xd0, 0x1a, 0x3c,
0x77, 0x50, 0x3f, 0x50, 0xce, 0x96, 0x3b, 0x1d, 0x51, 0x3f, 0xbd, 0x5e, 0x9c, 0x3f, 0xef, 0x9e, 0x55, 0xab, 0x77, 0x3b, 0x99, 0xa7, 0xa3, 0xc7,
0xa0, 0x4f, 0x1d, 0x4e, 0xca, 0x9f, 0x2e, 0x2b, 0x30, 0x88, 0xba, 0x30, 0xab, 0xf3, 0x6f, 0xf6, 0xe0, 0x5b, 0x2f, 0xec, 0x35, 0xf6, 0xb4, 0x93,
0x22, 0x6b, 0x67, 0x5d, 0x18, 0x90, 0xb5, 0x33, 0x18, 0x9a, 0xa4, 0x68, 0xc5, 0x56, 0x47, 0x36, 0x8f, 0xaf, 0xe7, 0xe8, 0x9b, 0x8e, 0xa0, 0x14,
0x0a, 0xff, 0x9d, 0xe1, 0x0a, 0x5a, 0x54, 0x83, 0xc7, 0x29, 0x85, 0x5d, 0x8f, 0x17, 0x35, 0x18, 0x44, 0x5d, 0x18, 0x91, 0xf5, 0x93, 0x2e, 0x0c,
0x54, 0xf7, 0x6b, 0xb9, 0xf2, 0xed, 0xa4, 0x74, 0x91, 0x7f, 0x98, 0x36, 0xc8, 0xfa, 0x09, 0x0c, 0x4d, 0x52, 0x34, 0x81, 0xbf, 0x4e, 0x70, 0x05,
0xef, 0x76, 0xb4, 0x61, 0xe7, 0x53, 0x09, 0x7f, 0x6a, 0x52, 0x7d, 0x70, 0x2d, 0xaa, 0xc3, 0xcf, 0x09, 0x85, 0x9d, 0x1f, 0xed, 0xd6, 0x0b, 0xd5,
0xdf, 0x9f, 0x77, 0x67, 0x95, 0x0a, 0x9b, 0x04, 0x4f, 0x9c, 0xd1, 0x90, 0xdb, 0x71, 0xe5, 0xbc, 0xf8, 0x30, 0x69, 0xdd, 0x6d, 0x19, 0x83, 0xce,
0x8a, 0x38, 0xe3, 0x2d, 0x6e, 0x07, 0x4f, 0x40, 0x71, 0x5d, 0xd1, 0x86, 0x37, 0x15, 0xfc, 0xa9, 0x2b, 0x8d, 0xfe, 0x7d, 0x6f, 0xd6, 0x9d, 0xd6,
0x68, 0x69, 0x4a, 0x03, 0x51, 0x66, 0x7b, 0xcf, 0x1d, 0xb2, 0x11, 0xc8, 0x6a, 0x7c, 0x1a, 0x5c, 0x73, 0xce, 0x40, 0x3a, 0x12, 0xac, 0x57, 0xba,
0xf0, 0x2a, 0x98, 0xf5, 0x0c, 0x91, 0xe7, 0xa4, 0x0c, 0x27, 0x89, 0x13, 0x1e, 0x3c, 0x3b, 0x25, 0x76, 0x47, 0xab, 0x02, 0xad, 0x09, 0x0d, 0x6a,
0x98, 0x99, 0x66, 0xa2, 0x20, 0x48, 0xb1, 0x26, 0x95, 0x50, 0xff, 0x98, 0xb9, 0xcd, 0x1d, 0x5f, 0xcc, 0x47, 0x60, 0x63, 0xea, 0x60, 0x5a, 0xb4,
0x71, 0xc2, 0x92, 0xed, 0x7d, 0x75, 0xb9, 0x31, 0x00, 0x89, 0x12, 0x93, 0x64, 0x51, 0x50, 0x72, 0x82, 0x22, 0x8f, 0x61, 0xd6, 0x9a, 0xca, 0x92,
0x84, 0x69, 0x38, 0x22, 0x61, 0x59, 0x87, 0x57, 0x12, 0x8e, 0x9a, 0x02, 0xa4, 0x24, 0x9d, 0x6c, 0xa2, 0x5d, 0x65, 0xce, 0x8d, 0x65, 0x36, 0x77,
0xf8, 0xa7, 0x54, 0x73, 0x3a, 0xc5, 0xf3, 0x6a, 0x5c, 0xe1, 0xc2, 0xf8, 0xf5, 0x45, 0x92, 0xa0, 0x25, 0x56, 0x62, 0x12, 0xe8, 0xe1, 0x28, 0x86,
0x26, 0x84, 0x32, 0x3b, 0x31, 0x27, 0x66, 0x6b, 0x62, 0x62, 0x52, 0x31, 0xe7, 0x3d, 0x4c, 0x93, 0xd0, 0x96, 0x89, 0x12, 0x9a, 0x78, 0xd9, 0xa4,
0xa6, 0x0e, 0x6f, 0x13, 0x20, 0x44, 0xb0, 0x89, 0xdc, 0x37, 0x0c, 0x0d, 0x8b, 0x67, 0xdf, 0xe4, 0x72, 0x46, 0xf1, 0x4f, 0x48, 0xe5, 0xb6, 0x92,
0x98, 0x18, 0x4e, 0xb8, 0xe3, 0x78, 0x50, 0x00, 0x03, 0x81, 0xd1, 0x0c, 0x4f, 0xe0, 0xf6, 0x9c, 0xc5, 0x65, 0x92, 0xcc, 0x28, 0xfe, 0x66, 0xa8,
0x7f, 0xd3, 0x08, 0x49, 0xd1, 0x98, 0xd1, 0x7c, 0x32, 0x16, 0x97, 0xcc, 0x2c, 0xe1, 0x66, 0x0a, 0x5f, 0x73, 0x34, 0xda, 0xe2, 0x04, 0xe9, 0x4e,
0x37, 0x39, 0x13, 0xe7, 0x7b, 0xb2, 0x70, 0x63, 0xe8, 0xba, 0x8d, 0xe1, 0x10, 0x41, 0x17, 0x1c, 0x04, 0x55, 0x53, 0xfc, 0x4d, 0xa3, 0x2b, 0xcd,
0x64, 0x81, 0x49, 0x58, 0x51, 0x17, 0x0e, 0xe1, 0x05, 0x60, 0x97, 0x47, 0xe0, 0x86, 0xb3, 0xf1, 0x48, 0x5e, 0x70, 0x5f, 0x17, 0x6c, 0xa4, 0xef,
0x19, 0x55, 0x5c, 0x22, 0x29, 0x43, 0x62, 0x99, 0xc3, 0x7c, 0x92, 0xa2, 0xc9, 0x2a, 0x91, 0xa3, 0x8b, 0x44, 0x4e, 0x50, 0x25, 0x2e, 0x65, 0xc7,
0x52, 0x2e, 0x83, 0xb2, 0x39, 0xc5, 0x4e, 0x00, 0xc7, 0xc9, 0x30, 0xdb, 0x6c, 0x78, 0x65, 0x20, 0x01, 0xcf, 0x22, 0xca, 0xe9, 0xf2, 0x02, 0x29,
0x51, 0xe6, 0xcd, 0x12, 0x8b, 0xc3, 0x8c, 0xc9, 0x61, 0xc6, 0xe2, 0x30, 0x39, 0x12, 0xff, 0x94, 0x8b, 0x69, 0x86, 0xcb, 0x78, 0x0d, 0x8b, 0x48,
0x63, 0x72, 0x28, 0xca, 0x63, 0x51, 0x16, 0x0d, 0xc4, 0x6c, 0xeb, 0x44, 0xca, 0x83, 0x11, 0xa0, 0xa0, 0xc2, 0x5c, 0x48, 0x65, 0x60, 0x25, 0x36,
0x50, 0x47, 0x54, 0x93, 0x71, 0x8b, 0xf6, 0x3d, 0x5a, 0x8d, 0x35, 0x6e, 0x97, 0x39, 0xc6, 0x65, 0xce, 0xe6, 0x32, 0xc7, 0xb8, 0x94, 0xd5, 0x91,
0x86, 0xf4, 0xd8, 0xa4, 0x6d, 0x1a, 0x6e, 0x56, 0xc7, 0x9a, 0x32, 0x83, 0xac, 0xca, 0x16, 0xe2, 0x36, 0x4d, 0x5b, 0x5e, 0x57, 0x62, 0xc6, 0xbe,
0x12, 0xa7, 0x32, 0x18, 0x8b, 0xdb, 0x5c, 0xb8, 0x81, 0x0c, 0x25, 0x2e, 0x4d, 0xfe, 0x1e, 0x3d, 0x8d, 0x0c, 0x61, 0x8a, 0xcc, 0xc4, 0xd4, 0x5d,
0x96, 0x23, 0x85, 0xbf, 0xe3, 0xbe, 0x98, 0xab, 0x92, 0xc2, 0x09, 0x64, 0x22, 0x3e, 0x7e, 0x47, 0x86, 0x36, 0x85, 0x22, 0x56, 0x1d, 0x13, 0xdf,
0xf1, 0x11, 0x2b, 0x42, 0xf7, 0xaf, 0xf0, 0x34, 0x3a, 0x36, 0x83, 0x6b, 0x3b, 0xbc, 0xf8, 0xc0, 0x2c, 0x2d, 0x39, 0xa2, 0x4f, 0x9e, 0x90, 0x60,
0xbe, 0xc0, 0xd0, 0x2e, 0xec, 0x47, 0x8e, 0xec, 0x42, 0xd1, 0xae, 0x72, 0x9f, 0xcf, 0x74, 0x45, 0x13, 0x24, 0xb2, 0xb8, 0x49, 0x18, 0xf8, 0x87,
0x84, 0xc8, 0x10, 0x42, 0x64, 0x09, 0x1c, 0x6a, 0xf8, 0xa1, 0x6b, 0x32, 0x96, 0x94, 0x06, 0x1e, 0xc4, 0xab, 0x56, 0x99, 0x6c, 0xa8, 0x97, 0x76,
0x5a, 0x88, 0x17, 0x42, 0xfe, 0x25, 0xd7, 0x17, 0xd8, 0x4a, 0x5e, 0x25, 0xe3, 0xbd, 0x40, 0x69, 0xdb, 0xad, 0x73, 0x05, 0xca, 0x11, 0x5a, 0x64,
0xa5, 0x97, 0xe1, 0x91, 0x62, 0x18, 0xca, 0x2c, 0x5a, 0x52, 0x67, 0x9c, 0xfd, 0x1d, 0x3d, 0x32, 0xa2, 0xd7, 0x7f, 0xb4, 0x14, 0x2f, 0xb8, 0xc2,
0x17, 0xf2, 0x84, 0xe5, 0x40, 0x9f, 0x38, 0xe4, 0x1c, 0xa6, 0x10, 0x49, 0xab, 0xbb, 0xcf, 0xb1, 0xfd, 0xac, 0x29, 0x70, 0x80, 0xf1, 0xa1, 0x66,
0x73, 0xa4, 0x99, 0x2f, 0x54, 0x8d, 0x98, 0xf0, 0x3b, 0x18, 0xb4, 0x7a, 0x59, 0xda, 0x74, 0x99, 0xd0, 0xae, 0x4f, 0x28, 0x15, 0x29, 0xef, 0xa1,
0x22, 0x06, 0xcb, 0x0e, 0x87, 0x0e, 0x2f, 0x2e, 0x16, 0xd6, 0x68, 0x1b, 0x9e, 0xc2, 0x24, 0xc3, 0xcc, 0x21, 0x92, 0x78, 0xc9, 0x72, 0x9f, 0xeb,
0x6b, 0x36, 0x28, 0xda, 0xae, 0x9f, 0xda, 0x71, 0x0e, 0xd6, 0x87, 0x4e, 0x06, 0x31, 0xf2, 0xb7, 0x31, 0x6a, 0x77, 0x4e, 0x22, 0xde, 0x09, 0xa7,
0xde, 0x86, 0xd7, 0x44, 0xd5, 0xb0, 0x32, 0x33, 0xe3, 0xb9, 0xcc, 0x63, 0x61, 0x96, 0x5c, 0x4e, 0x96, 0x75, 0x00, 0xd1, 0x75, 0x58, 0xca, 0x0f,
0xb1, 0x18, 0x18, 0xf8, 0x9c, 0x81, 0xea, 0xa2, 0x84, 0x2e, 0x4d, 0x23, 0x61, 0x8a, 0x07, 0x05, 0xbc, 0x2e, 0x75, 0x93, 0x4a, 0xa2, 0x21, 0xeb,
0x4c, 0x98, 0xe3, 0x26, 0xcd, 0xe0, 0xce, 0x4a, 0x33, 0x54, 0x3b, 0x49, 0x96, 0x93, 0x36, 0x1a, 0xcd, 0x54, 0x11, 0x8b, 0xc8, 0x89, 0x06, 0x4c,
0x87, 0xa1, 0x47, 0x4e, 0x63, 0x96, 0x33, 0xe9, 0xd4, 0x30, 0xd4, 0x23, 0x61, 0xa8, 0x21, 0x2b, 0xe8, 0x92, 0x19, 0x69, 0x8a, 0x0d, 0xb1, 0x2c,
0x77, 0xa1, 0xb9, 0xdc, 0x38, 0x61, 0x04, 0x85, 0x9f, 0x63, 0x0a, 0x59, 0x87, 0x7b, 0x30, 0xcb, 0x51, 0x55, 0xa5, 0x3d, 0x6c, 0x3d, 0x0a, 0x06,
0x4a, 0xbc, 0x46, 0xe9, 0x25, 0x58, 0x52, 0xcf, 0x3a, 0x79, 0x13, 0x8a, 0xb7, 0x98, 0x2a, 0xc7, 0x96, 0xa5, 0xef, 0xfb, 0x4a, 0xd9, 0x72, 0xe6,
0x90, 0xc5, 0xb9, 0x24, 0xc0, 0x62, 0xc7, 0xc0, 0x04, 0xeb, 0xaf, 0x9c, 0x90, 0x93, 0x34, 0x71, 0x86, 0x69, 0xe4, 0x29, 0xf9, 0x3a, 0xa5, 0x98,
0x41, 0xe8, 0x2f, 0xaa, 0x12, 0x06, 0x18, 0x73, 0x92, 0x8e, 0xfc, 0xf5, 0xe2, 0x49, 0x3d, 0xef, 0xcd, 0xe7, 0x90, 0x92, 0x3c, 0x4e, 0x76, 0x01,
0x32, 0x37, 0xc3, 0x75, 0x24, 0xa6, 0x76, 0x90, 0x1d, 0x16, 0x26, 0xc8, 0x1a, 0x3f, 0x02, 0x3e, 0xf8, 0x50, 0xed, 0x14, 0xd6, 0x14, 0xb2, 0xae,
0x30, 0xdb, 0x2f, 0xaf, 0xce, 0x04, 0x4b, 0xb6, 0x64, 0x96, 0x53, 0x55, 0x60, 0x88, 0x91, 0xa0, 0x98, 0x28, 0x04, 0xa0, 0x0a, 0x53, 0x5c, 0x49,
0x24, 0x0b, 0x95, 0xa9, 0x28, 0x09, 0x09, 0x42, 0x29, 0xe9, 0x95, 0x45, 0x82, 0x74, 0x0f, 0xba, 0xcb, 0xc6, 0x18, 0x59, 0x8c, 0x87, 0xea, 0xd3,
0xe5, 0x8c, 0xe9, 0x6b, 0x44, 0xc1, 0xf0, 0x59, 0x51, 0xc0, 0xac, 0xd0, 0x89, 0x64, 0x4b, 0x98, 0xce, 0x0b, 0xba, 0x8e, 0x54, 0xa9, 0x36, 0x91,
0xd1, 0x9c, 0xc1, 0x25, 0xac, 0x17, 0xc0, 0x16, 0x15, 0xaf, 0x0f, 0x7d, 0x15, 0x29, 0x45, 0x48, 0xa5, 0x03, 0x02, 0xe9, 0x82, 0x35, 0x59, 0x4b,
0x75, 0xb6, 0x24, 0x61, 0x78, 0xe6, 0x1a, 0xe8, 0x8a, 0x93, 0xe6, 0x04, 0x1e, 0x8c, 0x90, 0x97, 0x25, 0xcc, 0x0d, 0x1d, 0xf5, 0x39, 0x5c, 0xc2,
0x26, 0xf7, 0x56, 0x51, 0x31, 0x35, 0x9f, 0xa4, 0xa3, 0x39, 0x18, 0xa8, 0x07, 0x20, 0x1c, 0x81, 0xf1, 0x6a, 0x34, 0x58, 0xe9, 0x88, 0x13, 0x89,
0xbc, 0x46, 0x56, 0x0a, 0xe0, 0x16, 0x96, 0x96, 0x64, 0x45, 0x59, 0x46, 0xc9, 0xd6, 0x58, 0x57, 0x82, 0x32, 0x23, 0x40, 0x85, 0x57, 0x0b, 0x8c,
0xda, 0xe9, 0xa0, 0xdd, 0x02, 0xe4, 0x2d, 0x6a, 0x3e, 0x5b, 0x6f, 0xe4, 0xc9, 0x05, 0xe5, 0x1d, 0xce, 0xc0, 0x6c, 0xd5, 0x25, 0x12, 0x53, 0x00,
0x8b, 0x52, 0xf4, 0x71, 0x36, 0xbb, 0x17, 0x44, 0xed, 0x55, 0x8c, 0x11, 0x9f, 0xc8, 0xb4, 0x28, 0x2f, 0xab, 0x2a, 0x32, 0x8e, 0xfb, 0xed, 0x33,
0x0c, 0x2f, 0x5f, 0xed, 0xfb, 0xaa, 0xa8, 0xbd, 0x95, 0x2d, 0x42, 0x2f, 0xc0, 0xde, 0xa0, 0xc6, 0xb4, 0xf1, 0x5a, 0xd6, 0x28, 0xc9, 0x20, 0x73,
0xc0, 0x15, 0x36, 0xd4, 0x57, 0xb2, 0x85, 0x51, 0xfc, 0x7c, 0xe1, 0x41, 0xd3, 0x7b, 0x49, 0x36, 0xd6, 0xe3, 0x8d, 0xa0, 0xf8, 0x59, 0x6b, 0xdf,
0xf7, 0x76, 0xc6, 0x30, 0x45, 0xd2, 0x04, 0xfc, 0xf5, 0x8d, 0xe9, 0x29, 0x1f, 0xc9, 0xc6, 0xab, 0x39, 0x23, 0x04, 0xc3, 0x8c, 0x61, 0xc3, 0x5d,
0x8c, 0xcc, 0x0b, 0x45, 0x37, 0x2e, 0x34, 0x85, 0x47, 0xba, 0xde, 0x43, 0x97, 0x33, 0x8c, 0x13, 0x64, 0x0d, 0x0f, 0xc4, 0x37, 0xf0, 0x86, 0x49,
0x0f, 0x73, 0xa4, 0x1b, 0x09, 0x32, 0x84, 0xed, 0xd1, 0x33, 0x66, 0x12, 0x86, 0x4d, 0xd8, 0x10, 0xe2, 0x59, 0xa3, 0x16, 0xe8, 0xc1, 0x21, 0xf0,
0xe6, 0x20, 0xce, 0x02, 0xfb, 0xc2, 0xaa, 0x6f, 0x70, 0x06, 0x48, 0x75, 0x3e, 0xb6, 0x78, 0x8e, 0x3b, 0x37, 0x90, 0x69, 0x72, 0x35, 0xcb, 0x50,
0xc2, 0x14, 0x4d, 0x38, 0x07, 0xd2, 0x06, 0xd4, 0x01, 0x66, 0xae, 0x33, 0x72, 0x3d, 0x0e, 0x22, 0x1b, 0xc8, 0xaf, 0x3e, 0xa2, 0x2c, 0x2d, 0xb8,
0x9f, 0x9f, 0x60, 0xe7, 0x95, 0x64, 0x38, 0x09, 0x69, 0x20, 0x6f, 0xad, 0x25, 0x05, 0xe0, 0xa3, 0x34, 0x56, 0xd0, 0x9b, 0xc8, 0x23, 0x8b, 0x15,
0xd7, 0xeb, 0xf4, 0x7e, 0x64, 0x53, 0x5e, 0xa8, 0x14, 0xfb, 0x33, 0xc4, 0x1b, 0x48, 0xd2, 0xde, 0x60, 0xa0, 0x86, 0x40, 0x39, 0x0b, 0x38, 0xad,
0x5f, 0x29, 0xa7, 0x0d, 0x5d, 0x55, 0x64, 0x1d, 0x0d, 0xd0, 0x92, 0x0e, 0x09, 0x78, 0x9e, 0x73, 0xcd, 0xb4, 0xce, 0x0d, 0x4d, 0x04, 0xc6, 0x2e,
0x35, 0xe7, 0x83, 0x24, 0xdd, 0x8c, 0x79, 0x9c, 0x0f, 0xf1, 0x3d, 0x80, 0xd0, 0xc3, 0x0c, 0x99, 0x56, 0x2a, 0xed, 0x9b, 0xfa, 0xe5, 0x11, 0x97,
0x34, 0x06, 0xbc, 0xe9, 0x05, 0x18, 0x6d, 0x82, 0x8c, 0x83, 0x47, 0x3c, 0x62, 0x5e, 0x2a, 0x0f, 0x22, 0x4b, 0x4f, 0x3d, 0x0b, 0xe4, 0xe6, 0x0e,
0x00, 0x7c, 0xe8, 0x2f, 0xeb, 0x26, 0xd9, 0xa0, 0xab, 0xa3, 0xc4, 0x3c, 0x0f, 0xb9, 0x6d, 0x1b, 0xd0, 0x05, 0x75, 0x20, 0x4d, 0x00, 0x9a, 0x99,
0x32, 0x9a, 0x3c, 0x42, 0xaf, 0xc8, 0xe0, 0x79, 0x87, 0xed, 0x16, 0x7e, 0xdc, 0x67, 0x87, 0xd8, 0x4f, 0xa7, 0x39, 0x41, 0x41, 0x06, 0x28, 0xa9,
0xb2, 0xb5, 0x76, 0x14, 0x84, 0xcc, 0x2a, 0x32, 0xd1, 0x19, 0x96, 0x14, 0x7e, 0x71, 0xd1, 0xb9, 0xf8, 0x91, 0xcf, 0xf8, 0xa1, 0x32, 0xfc, 0xcf,
0xf1, 0x53, 0xc8, 0xa5, 0x83, 0xe6, 0x22, 0xd4, 0x4e, 0xd1, 0x1d, 0xf3, 0x65, 0xce, 0x2d, 0x04, 0x1d, 0xe9, 0x9a, 0x6a, 0xa2, 0x3e, 0x68, 0x94,
0x81, 0x08, 0x6f, 0x56, 0x05, 0x67, 0x65, 0xb6, 0x56, 0x37, 0x1f, 0x3d, 0xb2, 0xed, 0x7e, 0x90, 0x62, 0xda, 0xd1, 0xa0, 0xfb, 0x21, 0x0e, 0x16,
0xed, 0xd8, 0x40, 0x66, 0x9f, 0x27, 0xa8, 0x53, 0x48, 0x33, 0x6a, 0x38, 0xd0, 0x46, 0x80, 0x39, 0x39, 0x87, 0xd1, 0x98, 0x22, 0x23, 0xfc, 0x11,
0x37, 0x00, 0x93, 0x60, 0x2f, 0x2e, 0x07, 0x00, 0xc1, 0xe6, 0xb0, 0xbf, 0x0f, 0xed, 0x20, 0x81, 0x97, 0x15, 0xf1, 0x46, 0xd8, 0xa7, 0x53, 0x82,
0x66, 0x43, 0xe1, 0x74, 0x4c, 0xca, 0x22, 0x0d, 0x10, 0x41, 0x5d, 0xf9, 0x7e, 0x51, 0x19, 0xab, 0xd0, 0xa9, 0x2a, 0xcc, 0x34, 0x83, 0xf6, 0x19,
0x2c, 0x16, 0xe4, 0xe4, 0x25, 0x91, 0xbf, 0x67, 0x4e, 0x6c, 0x2d, 0x26, 0xfe, 0x65, 0xab, 0xcf, 0xdf, 0xa4, 0x2d, 0x95, 0xa6, 0x12, 0xe5, 0x61,
0x90, 0xcf, 0x8c, 0x5c, 0x1d, 0x93, 0x25, 0x69, 0xfd, 0xce, 0x38, 0xc1, 0x89, 0x91, 0x38, 0x81, 0x7d, 0x0d, 0x50, 0x61, 0x4c, 0x07, 0x50, 0x7c,
0x66, 0xd9, 0x24, 0x98, 0xd2, 0x09, 0x04, 0xaa, 0x49, 0x48, 0x0e, 0x1b, 0xd7, 0xf4, 0xb0, 0x05, 0x4c, 0x8f, 0xc0, 0x27, 0xb3, 0xf6, 0x1a, 0xec,
0x73, 0x4d, 0x76, 0xf1, 0x63, 0x76, 0xc4, 0x9a, 0x5e, 0x35, 0xe7, 0x9c, 0xa7, 0xbf, 0x25, 0x07, 0x8a, 0xf5, 0x7d, 0x8a, 0xfa, 0xbd, 0x2c, 0xa7,
0x2c, 0xf6, 0x28, 0x97, 0x9a, 0x14, 0x0e, 0xf5, 0xe2, 0x1b, 0xf6, 0xaf, 0xc7, 0x30, 0x04, 0x40, 0x29, 0xfe, 0xfc, 0xb2, 0x0f, 0x20, 0x7c, 0x01,
0x65, 0x56, 0x42, 0xf2, 0x04, 0x7c, 0xfc, 0x31, 0x53, 0xb0, 0x78, 0xf4, 0xcf, 0x4e, 0x7c, 0x34, 0xa0, 0x89, 0x89, 0xd9, 0xc4, 0x09, 0x48, 0x58,
0x77, 0x15, 0xf5, 0x3e, 0x0e, 0x8a, 0x97, 0x14, 0xd4, 0x7a, 0x05, 0xfe, 0x67, 0xc1, 0xf1, 0x08, 0xe2, 0x8a, 0x8a, 0x2c, 0xde, 0x73, 0x87, 0x8e,
0x9c, 0x08, 0x4c, 0x5a, 0x0c, 0x00, 0x4a, 0x9c, 0x6e, 0x9c, 0x59, 0xc0, 0x3a, 0x53, 0x28, 0x68, 0x57, 0x9e, 0x6e, 0xca, 0x93, 0x5d, 0x96, 0xce,
0x39, 0x53, 0x3b, 0xf9, 0xb0, 0x86, 0x19, 0xb3, 0x59, 0x8c, 0xa5, 0xcf, 0x28, 0xc5, 0xe7, 0xf9, 0x34, 0xd8, 0xd6, 0x21, 0x04, 0xf4, 0x69, 0xb0,
0x47, 0xba, 0xa1, 0xc1, 0xe4, 0x9e, 0x80, 0x2d, 0x87, 0x30, 0x32, 0x1e, 0x7a, 0x6b, 0x66, 0xa8, 0x5e, 0xa6, 0x58, 0x9f, 0x2c, 0xeb, 0x64, 0x36,
0xa5, 0xbd, 0x84, 0xab, 0xd8, 0xeb, 0xc1, 0x5e, 0xfc, 0x5e, 0x3c, 0x96, 0xd1, 0xe6, 0xb1, 0xe3, 0xbc, 0x34, 0x94, 0x18, 0xb0, 0x97, 0xa0, 0x73,
0xda, 0xe8, 0x5c, 0x8b, 0x4d, 0x42, 0x37, 0xf5, 0x46, 0x05, 0xf0, 0x09, 0x5b, 0x9b, 0x63, 0x05, 0xa9, 0x63, 0x98, 0xd4, 0x0e, 0xb8, 0x92, 0xcd,
0x1b, 0x94, 0xe6, 0xe5, 0xdf, 0x35, 0xcc, 0x48, 0x14, 0x91, 0x66, 0x5c, 0x68, 0xa8, 0xdf, 0xa8, 0x9b, 0x75, 0x71, 0x02, 0xc4, 0xa0, 0xda, 0x2f,
0xe2, 0xfe, 0x98, 0xff, 0x39, 0xed, 0x32, 0x81, 0x75, 0xe3, 0xaf, 0xd3, 0xf7, 0x67, 0x44, 0x6e, 0xda, 0x68, 0x08, 0x52, 0x11, 0x4c, 0xeb, 0xc4,
0x7f, 0xff, 0x00, 0x24, 0x2d, 0x83, 0xdc, 0x54, 0xda, 0xb7, 0xf5, 0x49, 0x86, 0x2e, 0x30, 0x2d, 0x15, 0x23, 0xdb, 0xe6, 0x58, 0xcb, 0x18, 0xcd,
0x84, 0x35, 0x63, 0x48, 0x1a, 0x63, 0xf8, 0xe4, 0x23, 0x91, 0x87, 0x1f, 0x9c, 0x0d, 0x4d, 0xcb, 0x80, 0xe0, 0x26, 0x05, 0x9b, 0x40, 0x51, 0x74,
0x1a, 0xdc, 0x34, 0x00, 0xe6, 0x12, 0xdf, 0x1d, 0xfe, 0x94, 0x4d, 0xfc, 0xfc, 0xca, 0x7b, 0x89, 0x51, 0x76, 0xc0, 0x5b, 0xbf, 0x84, 0xe6, 0xad,
0xf8, 0x4b, 0xf6, 0xe7, 0x54, 0x32, 0xf9, 0xdd, 0x97, 0xb9, 0x2c, 0x5a, 0x64, 0xfa, 0xa3, 0x71, 0x06, 0xb6, 0x10, 0x93, 0x29, 0x90, 0x8a, 0x11,
0x22, 0x3e, 0x61, 0x91, 0x4a, 0xfe, 0xb8, 0xfd, 0xb3, 0x1f, 0x11, 0x97, 0x90, 0x39, 0x4a, 0xa8, 0x97, 0x7f, 0xdf, 0x00, 0x24, 0x71, 0x54, 0x96,
0x13, 0xcc, 0xec, 0x37, 0xc9, 0x9f, 0xb2, 0x04, 0x33, 0x12, 0xcd, 0x11, 0xf3, 0x08, 0xfd, 0x63, 0xf1, 0xe7, 0xac, 0xc7, 0x20, 0x96, 0x8e, 0xcc,
0x06, 0x07, 0x46, 0xca, 0x98, 0x20, 0xe3, 0x71, 0x44, 0xf2, 0xe5, 0x63, 0x4e, 0xef, 0x5d, 0x86, 0x26, 0x69, 0x1d, 0xa4, 0xa7, 0x32, 0xbf, 0xb2,
0x58, 0x9d, 0x08, 0xc1, 0xe1, 0x84, 0x61, 0x2c, 0x81, 0xbf, 0x65, 0xf6, 0x7b, 0xe2, 0x2c, 0x1c, 0x83, 0xd2, 0x30, 0x2b, 0x20, 0x25, 0x09, 0xbe,
0x93, 0x66, 0x8b, 0xe4, 0xcb, 0x3b, 0x62, 0xf6, 0xbd, 0x33, 0x85, 0x5b, 0x42, 0xe0, 0xe0, 0xd1, 0x01, 0xb2, 0x90, 0xfa, 0xae, 0xfc, 0x53, 0x3e,
0x03, 0x7e, 0x91, 0x5f, 0xc2, 0xd8, 0xc1, 0x4a, 0xd8, 0xc4, 0x0d, 0x80, 0xf5, 0xe3, 0x2f, 0xf9, 0x9f, 0x33, 0xe9, 0xf4, 0x77, 0x5f, 0x14, 0xf2,
0x10, 0xb5, 0xb3, 0x78, 0x5b, 0x95, 0x4d, 0x12, 0x14, 0xfa, 0xc4, 0x06, 0x68, 0x81, 0xc4, 0x94, 0x4d, 0x2b, 0xfd, 0xe3, 0xe6, 0xcf, 0x21, 0x4c,
0x67, 0x39, 0x0f, 0xc2, 0x9d, 0x8a, 0x26, 0x26, 0x02, 0x79, 0x9a, 0xb0, 0x5c, 0x41, 0x50, 0xf3, 0x5f, 0xa7, 0x7f, 0xca, 0x13, 0xd4, 0x95, 0x78,
0x51, 0xdc, 0x3a, 0x3f, 0x53, 0x0c, 0x78, 0x1a, 0xf8, 0x1f, 0x90, 0xd6, 0x20, 0x10, 0x8e, 0x0f, 0xb5, 0x11, 0xc1, 0xc6, 0xa3, 0x8b, 0x6c, 0x52,
0x70, 0xef, 0x98, 0x2b, 0x6d, 0x29, 0xc7, 0x32, 0xbf, 0xfd, 0xe6, 0x32, 0x8c, 0x60, 0x1d, 0x27, 0x45, 0x0c, 0x32, 0x0c, 0x64, 0x4b, 0xfd, 0x2d,
0xe2, 0x08, 0x6f, 0xe4, 0x13, 0xce, 0x45, 0x85, 0xd0, 0x48, 0x59, 0x5c, 0xb7, 0x9b, 0x66, 0x6d, 0x92, 0x2f, 0xff, 0x30, 0xda, 0x0d, 0xcc, 0x2a,
0x78, 0x5a, 0xa6, 0x72, 0x45, 0x63, 0x3a, 0x0f, 0xde, 0xce, 0x59, 0xc7, 0x5e, 0x35, 0x84, 0xe4, 0x7e, 0x89, 0x64, 0x09, 0xab, 0x62, 0x25, 0x47,
0x4e, 0x6a, 0x3b, 0x69, 0x37, 0x16, 0x73, 0x09, 0xed, 0x9b, 0xe4, 0x07, 0x00, 0x43, 0xf4, 0xcf, 0xe3, 0xcd, 0x70, 0x3e, 0x4d, 0x70, 0xe8, 0x2f,
0x10, 0x3d, 0x58, 0x81, 0x53, 0xc4, 0x0a, 0xc6, 0x5a, 0x68, 0x9d, 0x44, 0x3e, 0x62, 0x5e, 0xf4, 0x61, 0xdc, 0xe9, 0x68, 0xcc, 0x30, 0xc8, 0xaf,
0x06, 0x5e, 0xac, 0x09, 0xc2, 0x7a, 0x03, 0x40, 0x12, 0x9a, 0xf4, 0x14, 0x31, 0x1f, 0xcb, 0xb2, 0xfb, 0x98, 0xe1, 0xc0, 0x0d, 0xc1, 0xdf, 0x80,
0x65, 0xdd, 0x4a, 0x47, 0x10, 0x1f, 0x5d, 0x58, 0x16, 0x06, 0x80, 0x81, 0xb5, 0x54, 0x04, 0xd7, 0x80, 0x69, 0x63, 0x05, 0x9e, 0xfb, 0xed, 0x37,
0xa8, 0xfa, 0x0f, 0x66, 0xa0, 0xef, 0xce, 0x9a, 0xbc, 0x35, 0x9e, 0xb7, 0x8f, 0x59, 0xc7, 0xf8, 0xaa, 0xa0, 0x84, 0x1e, 0x32, 0x84, 0x48, 0xc6,
0x28, 0x47, 0x44, 0x82, 0x78, 0x02, 0xad, 0x2a, 0x0b, 0x19, 0x7f, 0x13, 0x66, 0xc4, 0xdf, 0x38, 0x15, 0x6e, 0x09, 0xae, 0xfb, 0xc3, 0xdf, 0x4f,
0xb3, 0x20, 0x4a, 0xd8, 0xd4, 0xd2, 0x96, 0x60, 0xa2, 0x64, 0x48, 0x66, 0xcb, 0x38, 0xca, 0x6c, 0xa6, 0x9d, 0xe6, 0xd6, 0xc9, 0x41, 0x04, 0x82,
0x65, 0x2b, 0x99, 0xd5, 0x35, 0xde, 0xec, 0xca, 0x14, 0xfb, 0x9d, 0x55, 0x83, 0x3e, 0x44, 0x1e, 0x76, 0xd0, 0x15, 0xb7, 0xc4, 0xb3, 0x17, 0xa4,
0x7b, 0x62, 0x68, 0x73, 0xf7, 0x82, 0xed, 0x25, 0x92, 0x85, 0x0b, 0xaa, 0x87, 0xb1, 0x51, 0x1b, 0xcf, 0x40, 0xf8, 0x40, 0xcc, 0x49, 0x02, 0x9b,
0xc8, 0xf8, 0x1c, 0xb0, 0xb4, 0xcb, 0x58, 0x68, 0x19, 0x2f, 0x61, 0xb3, 0x0b, 0x4d, 0x5b, 0xb6, 0x14, 0x94, 0xe4, 0x47, 0x2f, 0x9a, 0x8d, 0x02,
0x66, 0xde, 0x12, 0x6b, 0x0d, 0xef, 0x5a, 0xb9, 0x47, 0x8a, 0xd5, 0x91, 0x70, 0x20, 0xb2, 0xf9, 0x03, 0x5b, 0x02, 0x79, 0x13, 0x51, 0xaf, 0x8e,
0x41, 0x48, 0x92, 0xdc, 0x0c, 0x03, 0xf5, 0x06, 0xe2, 0xc7, 0xe2, 0x6c, 0x23, 0x6d, 0xd2, 0xb4, 0xb9, 0x88, 0x80, 0x09, 0x4f, 0xb9, 0x47, 0xda,
0xc2, 0x80, 0x80, 0x27, 0xec, 0x56, 0x8a, 0x48, 0xb8, 0xc5, 0x32, 0x84, 0x5c, 0xc5, 0xdf, 0xc4, 0x48, 0xa8, 0x2a, 0x56, 0x35, 0xb6, 0x21, 0x31,
0xd6, 0x09, 0x3b, 0xe3, 0x96, 0xe6, 0x2e, 0xf6, 0x76, 0x3e, 0xff, 0xd5, 0x9c, 0x1c, 0x49, 0x56, 0x6d, 0xa4, 0xf3, 0xa6, 0x21, 0xb2, 0x6e, 0xcd,
0x11, 0x03, 0xcf, 0x66, 0xba, 0x84, 0x16, 0x58, 0xe9, 0x43, 0x6e, 0x6e, 0xf0, 0xdf, 0xd9, 0xb5, 0x87, 0x96, 0x31, 0xf3, 0xad, 0x6a, 0x5f, 0x96,
0x28, 0x47, 0x76, 0x72, 0x95, 0x26, 0x55, 0x59, 0x26, 0xf7, 0xed, 0xd6, 0xb0, 0x71, 0x4e, 0x35, 0xba, 0x06, 0x17, 0x3c, 0xed, 0x3d, 0x1e, 0x5a,
0x06, 0xe5, 0xe0, 0x81, 0x2d, 0xd5, 0x15, 0x09, 0x56, 0xdd, 0x78, 0x4b, 0xc7, 0x0b, 0xfe, 0x3c, 0xcb, 0x15, 0x63, 0xed, 0xe1, 0xed, 0x43, 0xdf,
0x39, 0x81, 0x93, 0xbb, 0x8e, 0x8e, 0x1c, 0x93, 0xc3, 0xbb, 0xbd, 0xeb, 0xf8, 0xb1, 0xfb, 0x34, 0x0c, 0x4a, 0x32, 0xca, 0x91, 0xb0, 0xfe, 0x25,
0xcc, 0x6d, 0x2e, 0x79, 0xe7, 0x1b, 0x24, 0x79, 0x8c, 0x04, 0x63, 0x27, 0xca, 0x81, 0x3c, 0x1d, 0x73, 0x20, 0xe6, 0x21, 0xbf, 0x91, 0x21, 0x72,
0xfd, 0x7e, 0x9a, 0x23, 0x1c, 0xac, 0x21, 0x2a, 0x89, 0x5e, 0xa2, 0x98, 0x6e, 0xf0, 0x1c, 0x21, 0x76, 0xc8, 0x4f, 0x85, 0x05, 0x3b, 0x7b, 0xb0,
0x8a, 0x87, 0x2c, 0xa5, 0x10, 0x20, 0x2c, 0xea, 0x15, 0x9a, 0xd7, 0x5c, 0x59, 0x2c, 0x7e, 0xb9, 0xcf, 0xc1, 0x6f, 0x96, 0x76, 0xa2, 0x05, 0x76,
0x33, 0xb4, 0x88, 0x90, 0x59, 0x33, 0xff, 0x19, 0x9c, 0x7a, 0x54, 0x59, 0x9e, 0x56, 0x98, 0x59, 0xda, 0xbe, 0x93, 0xd2, 0xa6, 0xa9, 0x6c, 0x9e,
0x78, 0x0f, 0x63, 0x84, 0x40, 0xd2, 0x37, 0xc3, 0x98, 0x6c, 0x05, 0x7c, 0x2b, 0x7c, 0xbb, 0x91, 0x40, 0x45, 0x60, 0xfa, 0x4a, 0x43, 0x53, 0x20,
0x38, 0x01, 0xf6, 0x58, 0x04, 0x7b, 0x8c, 0x53, 0xea, 0xdf, 0x56, 0x14, 0x4d, 0x81, 0x8f, 0x00, 0xa4, 0x70, 0x5a, 0xdd, 0xd5, 0x94, 0xc7, 0x02,
0x49, 0xe2, 0x54, 0x1d, 0x1d, 0xe7, 0xc8, 0x23, 0x7b, 0x14, 0x44, 0xdb, 0xf1, 0xce, 0xfc, 0x32, 0xeb, 0x9b, 0x29, 0x81, 0x99, 0x09, 0x29, 0x3e,
0x1c, 0x3b, 0xc1, 0x27, 0x9e, 0x12, 0x02, 0xf9, 0x0d, 0x87, 0x73, 0x1b, 0x93, 0xc1, 0xe8, 0xe9, 0x90, 0x33, 0x17, 0x08, 0x13, 0x4b, 0xc8, 0x2a,
0x7f, 0xa4, 0x08, 0x2b, 0x17, 0x11, 0xbd, 0xbc, 0xaa, 0x58, 0xfe, 0x24, 0x72, 0x80, 0x2c, 0xa6, 0xe3, 0x23, 0x4c, 0x49, 0x84, 0x49, 0xcb, 0x66,
0xb1, 0xe5, 0x3a, 0x9a, 0xb0, 0x95, 0xb4, 0xe7, 0x47, 0x1c, 0x0e, 0x78, 0x8d, 0xe6, 0x90, 0x97, 0x0c, 0x37, 0x22, 0x69, 0x9e, 0xe5, 0x9a, 0x23,
0xf1, 0x35, 0x34, 0x83, 0xcd, 0x6a, 0x53, 0x51, 0x92, 0x7f, 0x2d, 0x65, 0xe6, 0x28, 0x5d, 0x95, 0xde, 0xc4, 0x1b, 0xa1, 0x90, 0x0e, 0x4e, 0x45,
0x3d, 0x3a, 0xbd, 0x81, 0xd7, 0x60, 0xfa, 0xf4, 0x15, 0xdd, 0x11, 0xd2, 0x8c, 0xb3, 0xb0, 0xa3, 0x27, 0xe0, 0xfe, 0x95, 0xe2, 0x01, 0xde, 0xd5,
0x21, 0x94, 0x86, 0x0f, 0x8a, 0x16, 0x86, 0x69, 0xbe, 0x47, 0x97, 0x7d, 0xf8, 0xb6, 0xa6, 0x29, 0x8a, 0xa0, 0x9b, 0xe8, 0xa0, 0x40, 0x7e, 0xf2,
0x8e, 0xe2, 0x83, 0x68, 0xf1, 0x34, 0x4f, 0x86, 0x0e, 0xe2, 0xc6, 0x1b, 0xfb, 0x11, 0x78, 0x09, 0xc2, 0x2e, 0xf8, 0x24, 0x53, 0x45, 0x38, 0x2f,
0x2d, 0x51, 0xe5, 0x34, 0x28, 0xf8, 0x41, 0x11, 0xc2, 0xf4, 0x8f, 0x29, 0xe4, 0x72, 0xef, 0x10, 0x18, 0x6a, 0xd2, 0x93, 0x87, 0x8a, 0x59, 0x7d,
0x64, 0x79, 0x2c, 0x08, 0x00, 0xb8, 0x83, 0x2d, 0x66, 0x27, 0x49, 0xc8, 0xaa, 0xd9, 0x8e, 0x26, 0xb5, 0xe1, 0x39, 0x56, 0xb2, 0x91, 0x76, 0xe6,
0xbb, 0x75, 0xea, 0x87, 0xfe, 0xb1, 0xf0, 0x73, 0xd2, 0x47, 0x93, 0x44, 0x52, 0x1c, 0x3f, 0xf8, 0xf1, 0x0d, 0x34, 0x85, 0xf3, 0x04, 0x4c, 0x5b,
0xb0, 0x0d, 0x64, 0x10, 0x50, 0x73, 0xc0, 0xff, 0x83, 0xba, 0xdd, 0x9c, 0x4a, 0x68, 0x8d, 0xe6, 0xfc, 0x76, 0x7b, 0x05, 0xaf, 0xee, 0xcc, 0xc9,
0xd2, 0x63, 0x8e, 0x92, 0xda, 0x12, 0xfe, 0x17, 0xfe, 0xb2, 0x31, 0x82, 0x3a, 0xdd, 0x12, 0xd1, 0x31, 0x94, 0x48, 0x10, 0x8c, 0x96, 0x46, 0x75,
0xa7, 0x9c, 0xa3, 0xff, 0x7b, 0xf9, 0x03, 0x7a, 0xd9, 0xe7, 0x74, 0x49, 0xc0, 0x05, 0x5d, 0x52, 0xda, 0xfa, 0x8f, 0xc4, 0x4b, 0xd8, 0x01, 0x64,
0xd2, 0xf2, 0x5d, 0x5e, 0x97, 0x52, 0xf0, 0xc0, 0x90, 0xa2, 0x50, 0xb3, 0x2c, 0x21, 0x61, 0xb4, 0xd2, 0x2c, 0x61, 0xb1, 0x0e, 0x05, 0x3f, 0x68,
0x21, 0xd9, 0x42, 0xdb, 0x6c, 0x02, 0x38, 0xb1, 0xac, 0xc6, 0x4a, 0xd3, 0x52, 0x64, 0x37, 0x60, 0x12, 0x79, 0x11, 0x0b, 0x03, 0x10, 0xde, 0x20,
0xd6, 0xa4, 0x35, 0x3d, 0xef, 0xce, 0xc6, 0xda, 0x02, 0x38, 0xea, 0xa7, 0x8d, 0xdb, 0x4a, 0x13, 0xfa, 0x5e, 0xd5, 0x06, 0xa1, 0x7f, 0x2c, 0xfd,
0xf8, 0xa1, 0x8e, 0x03, 0xa2, 0xd5, 0x0b, 0x9a, 0x04, 0xa6, 0x40, 0x34, 0x9c, 0x0e, 0x12, 0x25, 0x11, 0x70, 0x13, 0x59, 0x04, 0x96, 0x39, 0x81,
0x58, 0x0d, 0xe9, 0x42, 0x13, 0x30, 0x18, 0x55, 0x1f, 0x33, 0xdb, 0x49, 0x7f, 0x56, 0xff, 0xb3, 0xf9, 0x3f, 0xe9, 0xa0, 0xa9, 0x2f, 0xe0, 0x6f,
0x0f, 0xb2, 0x15, 0x43, 0x99, 0x18, 0x3e, 0x5a, 0x64, 0xdc, 0x85, 0xc1, 0xe9, 0x2f, 0x1c, 0x32, 0x78, 0x56, 0xda, 0xff, 0xbf, 0xbb, 0xdf, 0xad,
0x3b, 0x81, 0x73, 0x64, 0x5b, 0x49, 0x2f, 0x4d, 0xa7, 0x97, 0xff, 0x2e, 0xbb, 0x83, 0xfe, 0x98, 0xa4, 0x7f, 0xdf, 0xe6, 0x90, 0x29, 0x09, 0x3f,
0x73, 0x7b, 0x09, 0x24, 0x53, 0x90, 0x84, 0x13, 0x9e, 0xef, 0xb1, 0x30, 0x10, 0x29, 0x8b, 0xb4, 0x20, 0x92, 0x73, 0x75, 0x2c, 0x28, 0x8c, 0x94,
0x93, 0x84, 0x07, 0xc8, 0x2c, 0x0b, 0xb3, 0xb1, 0x2a, 0x44, 0xcc, 0x86, 0xcc, 0x80, 0xec, 0xac, 0x77, 0x5d, 0x59, 0x62, 0x03, 0xde, 0xdc, 0xb6,
0x3d, 0x7d, 0xfb, 0x91, 0x62, 0xa5, 0xb7, 0xe8, 0x28, 0xa6, 0x84, 0xcc, 0x2b, 0x84, 0xdb, 0x0d, 0x94, 0x40, 0xb4, 0x37, 0x81, 0x48, 0xf7, 0x9c,
0xdc, 0xf9, 0x3f, 0x41, 0xa3, 0x91, 0xc1, 0x24, 0x11, 0xeb, 0xbf, 0x11, 0x66, 0xd5, 0x29, 0x14, 0x0d, 0x74, 0xa3, 0x3a, 0x93, 0x41, 0x86, 0xa3,
0x4a, 0x92, 0x90, 0x0d, 0x67, 0x8b, 0x41, 0x24, 0x53, 0xf7, 0xbe, 0xae, 0xf2, 0x03, 0x6e, 0x33, 0xed, 0xc3, 0xb6, 0x83, 0x2e, 0x86, 0x11, 0x24,
0xa1, 0x48, 0x61, 0x3d, 0x8f, 0xcf, 0x2d, 0xdb, 0xfd, 0x1e, 0xc0, 0x89, 0x46, 0x46, 0x62, 0x14, 0x82, 0x1b, 0x76, 0xc7, 0x36, 0x96, 0x0e, 0x12,
0x93, 0xf3, 0x0a, 0x49, 0x42, 0xfe, 0xe3, 0x3c, 0x38, 0xf1, 0x17, 0x54, 0x75, 0xfb, 0xfb, 0x6f, 0xb3, 0xbd, 0x97, 0x70, 0xc6, 0x06, 0x29, 0x38,
0x4f, 0x67, 0xf8, 0x30, 0xd9, 0x1b, 0x14, 0x65, 0x2e, 0xcc, 0xde, 0xaf, 0x75, 0xfc, 0x26, 0x6b, 0x63, 0x34, 0xfc, 0x50, 0xac, 0x30, 0xca, 0xde,
0x2b, 0xd7, 0x2a, 0xef, 0x9f, 0xa7, 0x28, 0x9f, 0xb9, 0xe2, 0xf5, 0xeb, 0x8e, 0x20, 0xd8, 0xb6, 0x9c, 0x49, 0x3e, 0x84, 0x95, 0x2c, 0x9b, 0x46,
0x7b, 0x27, 0x3b, 0x8b, 0x86, 0x07, 0xca, 0x2a, 0x0c, 0x75, 0x46, 0x66, 0x47, 0x36, 0x25, 0xc5, 0x76, 0x24, 0xfe, 0x21, 0x8a, 0x5d, 0x12, 0x82,
0x9d, 0xa5, 0x6a, 0x3f, 0x5e, 0xdc, 0x49, 0xcf, 0xbd, 0xa2, 0xff, 0x07, 0x12, 0xe1, 0xfe, 0x43, 0x01, 0x28, 0x89, 0xf2, 0x70, 0xda, 0x1a, 0xe4,
0x79, 0xa4, 0xff, 0x7d, 0xfc, 0x47, 0x6b, 0x34, 0xdc, 0xc7, 0xeb, 0x53, 0x62, 0xbd, 0x10, 0xec, 0x25, 0x8a, 0x16, 0x39, 0x71, 0xc1, 0xf2, 0xc3,
0x65, 0x51, 0x71, 0xda, 0x49, 0x20, 0xea, 0xe5, 0xd3, 0xb0, 0xea, 0x26, 0x31, 0x82, 0x30, 0x52, 0xa2, 0x0c, 0x5b, 0x44, 0xfa, 0xf3, 0x9f, 0xe8,
0x1b, 0x82, 0xcf, 0x81, 0x2d, 0x8c, 0x47, 0x0a, 0xfe, 0x8a, 0x6c, 0x15, 0xe2, 0x89, 0x1f, 0xa1, 0xda, 0x3a, 0xc1, 0x47, 0x01, 0x5f, 0xa3, 0x2e,
0xc1, 0xc4, 0x47, 0x82, 0x60, 0x01, 0x3c, 0x50, 0x20, 0x5f, 0xef, 0xe3, 0xb6, 0xc0, 0x7b, 0x0f, 0x8d, 0x79, 0xd6, 0x8b, 0xff, 0x48, 0x75, 0x05,
0xdf, 0xa9, 0xf9, 0x2e, 0xb2, 0xe6, 0xd0, 0xa9, 0xb1, 0x7e, 0x98, 0xcd, 0xad, 0x17, 0x2f, 0x88, 0xdf, 0x3c, 0x27, 0xda, 0x44, 0xfc, 0x60, 0x76,
0x39, 0x40, 0xe1, 0x2d, 0xb6, 0xe0, 0x70, 0x44, 0xb0, 0x49, 0xa7, 0xea, 0x69, 0xa4, 0x9f, 0x62, 0x75, 0xb6, 0xca, 0x43, 0x88, 0x89, 0xe7, 0x46,
0xbb, 0xc8, 0xaa, 0xcd, 0x8d, 0x62, 0x28, 0x7f, 0xab, 0x12, 0x6d, 0x0f, 0x6f, 0x9e, 0xe0, 0x9f, 0xe5, 0xac, 0xfe, 0x9f, 0x05, 0xfe, 0x24, 0xc5,
0x65, 0xc1, 0x4c, 0x00, 0x72, 0x08, 0xd9, 0xd5, 0x48, 0x60, 0x7c, 0xe2, 0xc6, 0xcd, 0x02, 0xe6, 0x44, 0x9b, 0xd7, 0xdc, 0xb6, 0x52, 0x88, 0xce,
0xc3, 0x05, 0x7b, 0x43, 0x60, 0x83, 0xd2, 0x38, 0x5a, 0xf7, 0x66, 0xfc, 0x03, 0x59, 0x58, 0xc8, 0x93, 0x4d, 0xd8, 0x8f, 0xe1, 0x3d, 0x95, 0x47,
0x3c, 0x16, 0x12, 0x0e, 0x1f, 0xc8, 0x62, 0x6d, 0x91, 0x6c, 0xd2, 0x7a, 0x0a, 0xbf, 0x4e, 0x52, 0x8c, 0xa0, 0xe2, 0xe3, 0x5c, 0xb0, 0xa2, 0xee,
0x68, 0x53, 0x04, 0xfc, 0x05, 0x1c, 0x6d, 0xa9, 0xcb, 0xf5, 0xe0, 0x54, 0x6b, 0xb0, 0x6d, 0x10, 0x90, 0xc2, 0xad, 0xf9, 0x2e, 0xb6, 0xa6, 0xec,
0x08, 0xf8, 0xdf, 0x06, 0xf6, 0x18, 0xbb, 0x69, 0x49, 0xde, 0x70, 0xc2, 0xd6, 0xd8, 0x0f, 0xac, 0x3d, 0x17, 0x28, 0xa6, 0xc9, 0x33, 0x38, 0xb0,
0x21, 0x12, 0x5c, 0xca, 0xd0, 0x79, 0xc8, 0x49, 0x65, 0x6d, 0x46, 0xf0, 0x12, 0x6e, 0xd3, 0xad, 0xfa, 0x2e, 0xb6, 0x6a, 0x75, 0xab, 0x18, 0x2a,
0xf4, 0xa0, 0x67, 0xf8, 0x3b, 0x68, 0x01, 0x83, 0x24, 0x89, 0x38, 0xe6, 0xd4, 0xac, 0x42, 0x1b, 0x44, 0x79, 0x30, 0x18, 0x00, 0x1d, 0x40, 0x4e,
0xc4, 0x2d, 0x8f, 0x32, 0x1e, 0xeb, 0xc8, 0xb8, 0xc6, 0x15, 0x7e, 0x68, 0x37, 0x1e, 0x1a, 0x1f, 0xc5, 0xf1, 0x00, 0xdf, 0x50, 0xe0, 0xb0, 0x40,
0x9a, 0xa6, 0x0b, 0x03, 0x3f, 0x25, 0x35, 0x11, 0x1a, 0x52, 0xe4, 0x99, 0xae, 0xea, 0xfd, 0xc9, 0x45, 0x9f, 0xad, 0xc4, 0x20, 0x84, 0x12, 0x65,
0x02, 0x77, 0x0a, 0xe0, 0x20, 0x6c, 0xd0, 0x61, 0x78, 0xb4, 0xe4, 0xd8, 0x1b, 0x24, 0x5f, 0xb5, 0x02, 0x9c, 0x89, 0x81, 0xbf, 0x80, 0xa9, 0x0d,
0xcb, 0x31, 0x51, 0x3c, 0xce, 0xb0, 0x3b, 0x65, 0xdf, 0x32, 0x09, 0xda, 0x7d, 0xb1, 0x02, 0x9e, 0x0a, 0x02, 0x7f, 0xbb, 0xd0, 0x3e, 0xd3, 0x67,
0x1b, 0x94, 0xeb, 0xa4, 0xbb, 0xf6, 0x06, 0x30, 0x40, 0xf9, 0x9e, 0x22, 0x36, 0xe5, 0x0f, 0x3d, 0x5c, 0x2a, 0xee, 0x7a, 0x28, 0x10, 0xf1, 0xba,
0x8c, 0x40, 0x3a, 0xc4, 0xe4, 0x1b, 0x66, 0xf0, 0xbf, 0x72, 0xfe, 0xf4, 0xd9, 0xb2, 0x04, 0x18, 0xbe, 0xae, 0xf4, 0xb9, 0x04, 0x17, 0x2f, 0x6c,
0x69, 0xdd, 0xf9, 0xbc, 0xbc, 0xc6, 0x37, 0x39, 0xa9, 0xf7, 0x16, 0xe2, 0x9b, 0x24, 0xe1, 0xc7, 0x1d, 0x7a, 0x65, 0xd2, 0x46, 0x23, 0x13, 0x59,
0xe8, 0xd2, 0x2a, 0x4d, 0x36, 0x5a, 0xd2, 0x0c, 0xbe, 0x1b, 0x15, 0x8c, 0xd7, 0xb8, 0x22, 0x04, 0x4e, 0xf3, 0x81, 0x51, 0xf0, 0xc7, 0xa4, 0x26,
0x44, 0x01, 0xea, 0x35, 0x53, 0x05, 0x80, 0xd3, 0x13, 0x36, 0x89, 0x04, 0x4e, 0x4f, 0x9a, 0x3a, 0xd5, 0xe0, 0x66, 0x09, 0x1c, 0x76, 0x8e, 0xf6,
0x21, 0xce, 0xd0, 0xbd, 0x8d, 0xe4, 0x77, 0x2c, 0x7b, 0x48, 0x4c, 0x2c, 0x22, 0xae, 0xae, 0x5c, 0xdb, 0x39, 0x20, 0x1d, 0x80, 0x33, 0xfc, 0x6e,
0x05, 0x4f, 0x29, 0xb2, 0xc1, 0x04, 0x36, 0xde, 0x52, 0x16, 0x48, 0xab, 0xd9, 0xb7, 0x5c, 0x8a, 0xf6, 0x0a, 0x65, 0x3c, 0xed, 0xad, 0xbd, 0x01,
0xc0, 0xd1, 0xfa, 0x84, 0xdf, 0x92, 0xe8, 0x69, 0xcb, 0x35, 0x2d, 0xe3, 0x0c, 0xe8, 0x03, 0x5f, 0x11, 0x46, 0x20, 0xfd, 0xc2, 0x38, 0x87, 0x89,
0xc9, 0xc4, 0xd3, 0x36, 0xc5, 0xc8, 0x62, 0x05, 0x55, 0xe8, 0xd1, 0x52, 0xfe, 0x2f, 0x9d, 0x63, 0x83, 0xaa, 0x77, 0x3f, 0x2f, 0xeb, 0x7a, 0x2c,
0x73, 0x0b, 0xc9, 0xd3, 0x4e, 0x80, 0x5b, 0x8f, 0x65, 0x13, 0x12, 0x01, 0x37, 0xf1, 0x7f, 0x86, 0x04, 0xba, 0x44, 0xcb, 0x92, 0x5d, 0x9f, 0x2c,
0x90, 0x38, 0xd3, 0x93, 0x37, 0x12, 0x36, 0xd5, 0x90, 0xdc, 0x10, 0xae, 0x87, 0xef, 0xd3, 0x45, 0x44, 0xb0, 0x00, 0xb6, 0xd6, 0x54, 0x02, 0xf0,
0x5a, 0x70, 0xa4, 0xc5, 0x0d, 0x41, 0xa3, 0x0d, 0xbb, 0x2e, 0xac, 0xb3, 0xf4, 0xe8, 0x53, 0x2a, 0x45, 0xc8, 0x73, 0x74, 0x8f, 0x25, 0xfd, 0x1d,
0x80, 0xe2, 0x59, 0x88, 0x2d, 0x9d, 0x69, 0x8e, 0xa0, 0xd8, 0xf9, 0x3a, 0xcf, 0x97, 0x89, 0xbd, 0x65, 0xe0, 0x57, 0x86, 0x6c, 0x79, 0x81, 0xc9,
0x19, 0x51, 0x16, 0xe7, 0xe6, 0x41, 0xb1, 0x55, 0x7a, 0xd2, 0xc9, 0x52, 0x9f, 0x69, 0x73, 0x64, 0xd4, 0xe0, 0x1e, 0x45, 0x2a, 0x64, 0x55, 0xf4,
0xa6, 0x53, 0xaf, 0xc3, 0xf8, 0x80, 0x2d, 0x5f, 0x95, 0x9b, 0x90, 0x93, 0x14, 0xed, 0x92, 0xb6, 0xf1, 0x64, 0xe3, 0x6f, 0x9d, 0xa2, 0xe4, 0xb1,
0xa4, 0x3e, 0x80, 0xb0, 0x89, 0xd1, 0x64, 0x38, 0x4d, 0x92, 0x46, 0xfe, 0xa6, 0x6a, 0xf4, 0xe8, 0x30, 0xdb, 0xd3, 0xf2, 0xb5, 0x14, 0x66, 0xd8,
0x69, 0xd6, 0xbf, 0x69, 0x4d, 0xa0, 0xe3, 0x5b, 0x78, 0x59, 0xe3, 0x60, 0x67, 0xe8, 0x84, 0x46, 0x18, 0x26, 0xd1, 0x04, 0xe6, 0x8f, 0xa1, 0x99,
0x8f, 0xd6, 0x63, 0xe3, 0xd6, 0xcd, 0x92, 0xf7, 0xda, 0x39, 0x46, 0x21, 0x2e, 0xd2, 0x2b, 0xc3, 0x5c, 0x06, 0x48, 0x1b, 0x5d, 0x11, 0x6a, 0x3a,
0x09, 0xaf, 0xd7, 0x1c, 0x3f, 0x63, 0x28, 0x8a, 0x7d, 0xc0, 0x8c, 0x3c, 0xc0, 0x4b, 0x43, 0x41, 0x1b, 0x2a, 0xb1, 0xc1, 0x38, 0x42, 0x32, 0x03,
0xc1, 0x45, 0x46, 0x36, 0x00, 0xf2, 0xfe, 0x21, 0xe4, 0xec, 0x8f, 0xda, 0x05, 0x15, 0xcf, 0x96, 0x8a, 0x8a, 0xf2, 0x78, 0x6b, 0x00, 0x54, 0x7c,
0xb7, 0x77, 0x3e, 0xc7, 0x74, 0xec, 0x5d, 0x52, 0x96, 0xf9, 0xfa, 0x6b, 0x44, 0xcf, 0xa2, 0x39, 0x6a, 0x75, 0x01, 0x4c, 0x18, 0x34, 0xb0, 0x37,
0x47, 0x1d, 0x66, 0xb3, 0xd6, 0x33, 0xe6, 0xce, 0xfa, 0xcd, 0xae, 0x1d, 0xad, 0x0b, 0x63, 0x72, 0x4a, 0x38, 0x08, 0x11, 0x35, 0x7d, 0x32, 0xb6,
0x31, 0x04, 0xef, 0xd5, 0x83, 0x97, 0xd4, 0x87, 0x8d, 0x5e, 0xd8, 0x77, 0xb3, 0x24, 0x31, 0x15, 0x9e, 0x90, 0x83, 0x7b, 0xec, 0x04, 0x7e, 0x2d,
0x07, 0x34, 0x4b, 0x07, 0x7f, 0xfa, 0xe8, 0x26, 0x0d, 0xc5, 0xd8, 0xc9, 0xb3, 0xaf, 0x1a, 0x02, 0x6c, 0x26, 0xfb, 0x0c, 0xdf, 0xbe, 0x5e, 0xf4,
0x27, 0xfa, 0xa4, 0xc0, 0xbc, 0xb5, 0x41, 0xf1, 0x97, 0x67, 0x27, 0x49, 0x76, 0xe3, 0xc7, 0x38, 0x24, 0xb7, 0xb6, 0xd6, 0x69, 0x41, 0x8e, 0xe2,
0xcb, 0xaf, 0x19, 0xdc, 0x58, 0xdc, 0x98, 0xbe, 0xeb, 0xf3, 0xf5, 0xc2, 0x38, 0xc7, 0x01, 0xc9, 0x2f, 0xb8, 0x15, 0xcb, 0x87, 0x61, 0xde, 0x61,
0xd9, 0xb5, 0x4e, 0x86, 0xf7, 0x6f, 0x48, 0xcf, 0x92, 0xf6, 0x23, 0xdd, 0x64, 0xb9, 0x9b, 0xb8, 0xce, 0x65, 0xae, 0xcf, 0x30, 0x21, 0x67, 0x2b,
0xe5, 0x1a, 0x9e, 0x9d, 0x9d, 0x9b, 0xb8, 0xaa, 0xfb, 0xdb, 0xfd, 0xa2, 0x97, 0xe7, 0xbe, 0xfa, 0xca, 0xd5, 0x09, 0x6b, 0xd7, 0xfe, 0x8d, 0xf9,
0x25, 0x6b, 0x9a, 0xf0, 0xed, 0xf3, 0x8c, 0x6f, 0x73, 0x8c, 0x70, 0x04, 0xb3, 0x9f, 0xf9, 0xe5, 0xe3, 0x88, 0x20, 0xae, 0x3f, 0xaa, 0x49, 0x7d,
0xb9, 0x05, 0x2b, 0xb9, 0x04, 0xcd, 0xb0, 0xdb, 0x6b, 0x12, 0x03, 0xcd, 0xe4, 0xb0, 0xc6, 0x47, 0xc9, 0x0e, 0x1d, 0x3d, 0xfc, 0x15, 0xe3, 0x9e,
0xf4, 0xf7, 0x26, 0xa0, 0x28, 0xc9, 0xcd, 0x49, 0x28, 0x09, 0x9c, 0x02, 0xb4, 0x95, 0xe4, 0xf4, 0x01, 0x51, 0x2b, 0x85, 0x16, 0xed, 0x7d, 0x92,
0x69, 0xd1, 0xb2, 0x0d, 0xdf, 0x41, 0x9f, 0x04, 0xd9, 0x9b, 0x04, 0x98, 0xbf, 0x21, 0x23, 0x4a, 0xda, 0x5e, 0x73, 0xd4, 0x63, 0xa9, 0x93, 0xfa,
0xfc, 0x11, 0x7c, 0x1d, 0x03, 0x3c, 0x7c, 0xa7, 0x52, 0xc1, 0x9c, 0x32, 0xb6, 0xcf, 0x56, 0x88, 0xe8, 0x54, 0xbb, 0xd9, 0xe5, 0xbf, 0x25, 0x33,
0x21, 0x62, 0xd1, 0xfa, 0x51, 0xfc, 0xf9, 0x28, 0x14, 0xa0, 0x26, 0x05, 0x4c, 0x38, 0x88, 0x77, 0xa8, 0x2b, 0xf9, 0x26, 0x1b, 0x49, 0x6b, 0xe8,
0x56, 0x89, 0xb8, 0xd8, 0x74, 0xc0, 0x27, 0xd6, 0x71, 0x66, 0xbf, 0xb9, 0xf0, 0x9f, 0xe0, 0x39, 0x6d, 0x99, 0xb3, 0x84, 0xfb, 0xa0, 0xef, 0x7c,
0x9b, 0xb8, 0x40, 0x3e, 0x34, 0x5a, 0x22, 0x24, 0xb0, 0xeb, 0x31, 0x7f, 0xbd, 0xeb, 0x84, 0xc3, 0xe5, 0x67, 0xb0, 0x3c, 0x4c, 0xd1, 0x5c, 0xbf,
0xe2, 0xb8, 0x29, 0x9e, 0x49, 0x5a, 0x74, 0x03, 0x73, 0x94, 0x8f, 0x72, 0xb3, 0xc0, 0xb1, 0xd0, 0xd4, 0x7c, 0x7b, 0xbe, 0x8b, 0x12, 0x4d, 0x90,
0x80, 0xdc, 0xfa, 0x9d, 0x3b, 0x4a, 0x36, 0xc4, 0x44, 0x36, 0x18, 0x84, 0xf3, 0x52, 0xc0, 0x65, 0x90, 0x46, 0x6d, 0x63, 0x09, 0x9e, 0x5d, 0x4a,
0x3f, 0x75, 0xf7, 0xfc, 0x9a, 0xe3, 0x45, 0x18, 0x83, 0x9c, 0x11, 0x7a, 0x91, 0xfd, 0x53, 0x00, 0x2a, 0xee, 0xc3, 0xd7, 0x01, 0x20, 0xc0, 0x77,
0xd3, 0xa1, 0x1c, 0x7d, 0x21, 0x1a, 0x20, 0x36, 0x80, 0x05, 0x7d, 0x0d, 0x26, 0x13, 0x91, 0xd8, 0x26, 0x64, 0x6c, 0x6a, 0x3f, 0xca, 0x3f, 0xef,
0x38, 0x72, 0x38, 0x7c, 0x0d, 0x67, 0xaf, 0x0f, 0x43, 0x6a, 0xc8, 0xa9, 0x47, 0x43, 0xd4, 0x95, 0xf0, 0xea, 0x13, 0x97, 0x33, 0x37, 0x7d, 0x68,
0x9d, 0xe8, 0x1a, 0x29, 0xa2, 0xea, 0x4e, 0x8f, 0xac, 0x50, 0xe4, 0x88, 0x1f, 0x54, 0x0f, 0x8d, 0x02, 0x86, 0x0d, 0x2d, 0x44, 0x06, 0x5b, 0x84,
0x2a, 0x3e, 0xaa, 0x99, 0x28, 0x78, 0x55, 0x8d, 0xaa, 0xd1, 0xa3, 0x9a, 0x06, 0xf6, 0x4d, 0xec, 0x11, 0x87, 0x5d, 0x49, 0xed, 0xd4, 0xa6, 0x1c,
0x5f, 0x06, 0x38, 0x76, 0x06, 0x35, 0xf1, 0xb2, 0x71, 0x8e, 0xd1, 0x5a, 0x9a, 0xcf, 0x02, 0xb4, 0xc3, 0x04, 0x57, 0xec, 0x2d, 0x52, 0xc2, 0x91,
0x08, 0xa6, 0x8b, 0xdb, 0xd8, 0xeb, 0x24, 0xa6, 0xfc, 0x67, 0x76, 0x3b, 0x36, 0xb3, 0xda, 0x42, 0x82, 0x59, 0xc3, 0x8f, 0x6b, 0x1d, 0x9c, 0xc2,
0x5c, 0xb5, 0x8d, 0xea, 0x28, 0x35, 0xaa, 0x66, 0x22, 0x8e, 0x23, 0x6a, 0x28, 0xe4, 0xf0, 0xd3, 0x2b, 0x4f, 0x1a, 0x99, 0x73, 0xd9, 0x02, 0x05,
0x44, 0x5e, 0xf9, 0x8b, 0xb4, 0x6b, 0x4c, 0x45, 0xdd, 0x7d, 0x12, 0xda, 0x00, 0x5c, 0x84, 0x3f, 0x02, 0xb7, 0x0f, 0xc7, 0xeb, 0xe1, 0x6c, 0x73,
0x35, 0x5d, 0x58, 0x4a, 0xf6, 0x6e, 0x69, 0xf9, 0xf7, 0x87, 0xb6, 0x72, 0x39, 0xaa, 0x8a, 0x1c, 0x46, 0x5a, 0x52, 0xa5, 0xc4, 0xd5, 0xdd, 0x99,
0x5b, 0x64, 0x2f, 0xca, 0x7f, 0xbe, 0x8b, 0xd2, 0x82, 0x5a, 0xda, 0xb0, 0xf1, 0x35, 0x9a, 0x1a, 0x57, 0x27, 0xc6, 0x36, 0x15, 0x8b, 0xa1, 0xeb,
0xff, 0xb0, 0x92, 0x67, 0x42, 0xb5, 0x0a, 0xdd, 0x93, 0x6a, 0x9e, 0x4c, 0xb1, 0x55, 0x66, 0x2c, 0x0f, 0x8b, 0x30, 0xe3, 0xee, 0xb0, 0x27, 0x3e,
0xaa, 0xc1, 0x29, 0xd5, 0x06, 0x4e, 0x93, 0xd8, 0x72, 0xe3, 0xde, 0x32, 0x39, 0xe1, 0xb1, 0x62, 0x1b, 0x87, 0x7a, 0x94, 0x04, 0xbe, 0x82, 0x85,
0x65, 0x84, 0x7c, 0x05, 0x8e, 0x88, 0x05, 0x25, 0x01, 0x7a, 0x1f, 0xba, 0xa9, 0xff, 0x5c, 0x53, 0x80, 0x5b, 0xdb, 0xb1, 0x3d, 0xa7, 0xc7, 0x56,
0xf9, 0xfb, 0xf1, 0xb1, 0x45, 0xd4, 0xc6, 0x6f, 0xf0, 0x14, 0x5b, 0xe8, 0x8d, 0xe5, 0x51, 0x5c, 0x95, 0x2c, 0x6a, 0x7f, 0xad, 0xae, 0xad, 0x89,
0xa1, 0x2d, 0x9c, 0xb9, 0xac, 0x8c, 0xcc, 0xae, 0x0d, 0x98, 0x8a, 0xd3, 0x6c, 0x7a, 0x4f, 0x8b, 0x7b, 0x66, 0x1a, 0x47, 0xe5, 0xfe, 0x5d, 0xb8,
0xf7, 0xa4, 0xf2, 0x2d, 0x07, 0xfa, 0xa3, 0x8f, 0xf4, 0x07, 0x00, 0x99, 0xe0, 0x7e, 0xd6, 0x46, 0x61, 0x83, 0x6c, 0x9e, 0x85, 0x0e, 0xb4, 0x51,
0x8f, 0x3a, 0xe3, 0x1f, 0xe8, 0xfa, 0x37, 0x99, 0x6c, 0x94, 0xe1, 0x7e, 0x6a, 0x50, 0xcd, 0x5a, 0x0f, 0x1e, 0xca, 0xf2, 0x4d, 0xca, 0x76, 0xa1,
0x8c, 0xf9, 0xc6, 0x35, 0xe2, 0x50, 0x79, 0x3e, 0xcc, 0xa0, 0x3f, 0xc8, 0x77, 0x62, 0x2e, 0xd2, 0x89, 0x39, 0x3c, 0x2d, 0x3b, 0xd0, 0x59, 0x12,
0xac, 0xff, 0x2c, 0xe3, 0x8e, 0x65, 0xe2, 0x96, 0xa1, 0xfb, 0x9e, 0x63, 0xb0, 0x26, 0xd8, 0x21, 0xa7, 0xcc, 0x90, 0xaf, 0xd0, 0xa9, 0xb8, 0xb0,
0x78, 0xc4, 0xf0, 0x79, 0xc5, 0x49, 0xd0, 0xdb, 0x67, 0x88, 0xff, 0x8c, 0x38, 0x98, 0xe2, 0xfb, 0x6e, 0x60, 0xff, 0x09, 0x41, 0x4a, 0xfc, 0xe6,
0x0b, 0x1c, 0x64, 0xe0, 0x39, 0x2d, 0x7c, 0xcc, 0x91, 0x72, 0xf3, 0xe6, 0x75, 0xf8, 0xec, 0x5e, 0xcc, 0x19, 0x35, 0x9c, 0x4c, 0xad, 0x0d, 0x59,
0x86, 0x49, 0x75, 0xdd, 0x01, 0xf2, 0x6a, 0xad, 0x55, 0x1b, 0xd4, 0xde, 0x3f, 0x87, 0x6d, 0xc7, 0xb5, 0x04, 0x5a, 0xfb, 0xaa, 0x6b, 0x10, 0xf1,
0x71, 0x84, 0x3c, 0xa8, 0x38, 0x30, 0x99, 0xca, 0xc8, 0x8e, 0xca, 0xff, 0x17, 0x21, 0xc2, 0x90, 0xdc, 0xbb, 0x5d, 0x8d, 0x08, 0xdb, 0xc1, 0xeb,
0x4c, 0x97, 0x92, 0xcb, 0xf1, 0x60, 0x0c, 0x1a, 0xc9, 0x18, 0x81, 0xb5, 0x8c, 0x38, 0xd6, 0x94, 0xdf, 0xc9, 0xa0, 0x13, 0x9b, 0x75, 0xb4, 0x50,
0x6f, 0x74, 0x38, 0x27, 0xd4, 0xe1, 0x44, 0xac, 0x1c, 0xce, 0xfb, 0x9d, 0xef, 0x67, 0xe2, 0xef, 0x65, 0xe8, 0x7f, 0x9a, 0xb9, 0x27, 0x33, 0x7a,
0x1f, 0xb0, 0x69, 0xc3, 0xba, 0x3b, 0xd4, 0xb9, 0xc4, 0xbe, 0x02, 0x14, 0xc7, 0xf4, 0x03, 0x05, 0xc9, 0x9c, 0x66, 0xdc, 0x3c, 0xe4, 0xee, 0x23,
0x50, 0x89, 0x69, 0xba, 0xde, 0x06, 0xe3, 0x1b, 0x93, 0x1b, 0x2b, 0xbe, 0x38, 0xe7, 0xab, 0xff, 0x9c, 0x2b, 0x30, 0x64, 0x3c, 0xba, 0x6d, 0xbc,
0x61, 0x91, 0x6e, 0x88, 0x81, 0x4b, 0xcc, 0xa0, 0x51, 0xa3, 0xd7, 0x08, 0xd7, 0xd1, 0x7b, 0x76, 0xf7, 0x85, 0xd1, 0x5d, 0x7a, 0xd0, 0xfe, 0xa8,
0x70, 0x2c, 0xfe, 0x1d, 0x5c, 0xde, 0x38, 0x61, 0xc9, 0xb1, 0x54, 0x9a, 0x7e, 0x56, 0xef, 0xd7, 0xdf, 0x76, 0xd4, 0x3e, 0x42, 0x83, 0x60, 0x44,
0xc6, 0x8a, 0xb6, 0x09, 0x79, 0x2e, 0xd1, 0x38, 0xdd, 0xe9, 0x11, 0x60, 0xb5, 0xa1, 0x13, 0xf3, 0xff, 0xc9, 0x0e, 0xa7, 0x50, 0x10, 0xc1, 0x3e,
0x42, 0x33, 0xac, 0x1e, 0xf1, 0xaa, 0x25, 0xae, 0xb7, 0xa3, 0x16, 0x42, 0x0c, 0x92, 0xbf, 0x82, 0x31, 0xb0, 0xda, 0x1f, 0x1d, 0x52, 0x7f, 0x14,
0x62, 0x90, 0xa3, 0x0d, 0x67, 0xae, 0xc9, 0xcb, 0xc2, 0xec, 0xdb, 0xa3, 0xb3, 0x36, 0x39, 0xed, 0x75, 0x7e, 0xc0, 0x06, 0x0f, 0x4b, 0xfe, 0x48,
0xd4, 0xe2, 0xd3, 0xe4, 0x45, 0x63, 0x69, 0xc0, 0x87, 0x42, 0xf8, 0x5a, 0xd7, 0xb3, 0xd6, 0xad, 0xaa, 0xb0, 0x6e, 0x98, 0x4d, 0xfb, 0x5b, 0x5d,
0xa9, 0x74, 0xe0, 0x06, 0xcd, 0xb4, 0x05, 0x70, 0x75, 0xb8, 0x83, 0x5d, 0xc3, 0xbc, 0xbc, 0x68, 0x6b, 0x98, 0x1a, 0xe9, 0x91, 0x24, 0xc8, 0xc4,
0xa7, 0xe3, 0xc4, 0x3f, 0xd0, 0x9d, 0x61, 0x48, 0x28, 0x92, 0x7b, 0x92, 0x2c, 0x9a, 0x75, 0x7a, 0xfd, 0x02, 0x47, 0xfa, 0xdf, 0xc1, 0xf5, 0x97,
0x12, 0x27, 0xca, 0xec, 0x87, 0xdc, 0x5b, 0xf8, 0xc0, 0x28, 0x93, 0x2c, 0x43, 0x9e, 0x1c, 0xd4, 0xa5, 0x79, 0xb5, 0x25, 0x36, 0xa2, 0xce, 0x14,
0x2e, 0xfc, 0x3c, 0x32, 0x23, 0xd0, 0xd0, 0xfd, 0x51, 0xd4, 0xca, 0xc2, 0xb6, 0x0c, 0x70, 0x3b, 0x07, 0xf8, 0x30, 0x2c, 0xbb, 0x73, 0x42, 0xea,
0x46, 0xa0, 0xeb, 0x8c, 0xf5, 0xf0, 0x77, 0xba, 0x0b, 0xfc, 0x8e, 0x7b, 0x49, 0xec, 0x13, 0xa9, 0xc9, 0x90, 0x00, 0x66, 0x7f, 0xf5, 0xd9, 0x74,
0xe4, 0xe8, 0xc5, 0xde, 0xf5, 0x48, 0xbc, 0x0b, 0x87, 0xff, 0x15, 0x56, 0xf2, 0x52, 0x3c, 0xe7, 0x1a, 0x32, 0x1d, 0x0b, 0x59, 0xf2, 0x4a, 0xbd,
0x13, 0xeb, 0xc1, 0x01, 0xe0, 0x95, 0x08, 0x91, 0xab, 0x10, 0x3d, 0xba, 0x2c, 0x90, 0x80, 0x42, 0xf8, 0x7a, 0xd2, 0xd9, 0xb0, 0x0e, 0x1b, 0xef,
0x4a, 0x9d, 0xaa, 0x6f, 0x59, 0x6d, 0x29, 0xf2, 0xab, 0x16, 0x3c, 0x54, 0x19, 0x00, 0x36, 0xe0, 0xda, 0x7f, 0x83, 0x0e, 0xa1, 0x90, 0x1f, 0x70,
0x0a, 0xdc, 0xb1, 0x71, 0x7c, 0x86, 0x65, 0xf1, 0x04, 0xcd, 0xe7, 0x5d, 0xc7, 0x28, 0xa1, 0x49, 0x2e, 0xda, 0x2a, 0x82, 0xac, 0xf2, 0xef, 0x74,
0x83, 0xd6, 0x42, 0x2f, 0x82, 0x7a, 0x73, 0x9f, 0x49, 0xb3, 0x14, 0x06, 0xeb, 0xe3, 0x5d, 0xa3, 0x56, 0xb2, 0x80, 0x09, 0xf2, 0xc9, 0x0d, 0x41,
0x12, 0xb9, 0x1d, 0x96, 0xb5, 0xae, 0x82, 0x04, 0xf1, 0x49, 0x23, 0x01, 0x4f, 0xf7, 0xfb, 0xb1, 0x8b, 0x17, 0x07, 0x83, 0x2e, 0x65, 0x56, 0x20,
0xfc, 0xe7, 0xcf, 0xfc, 0xcc, 0x47, 0x8e, 0x8f, 0xe4, 0x46, 0x0e, 0xc9, 0xdc, 0x99, 0x1e, 0xf8, 0x3b, 0xe1, 0x51, 0xa0, 0x57, 0xc5, 0x57, 0x60,
0xc0, 0x0b, 0x34, 0x41, 0x8a, 0xed, 0x8b, 0xc8, 0x33, 0x18, 0xbc, 0x51, 0x89, 0x1e, 0x24, 0xf1, 0x57, 0x58, 0xad, 0xac, 0x80, 0x07, 0x88, 0x75,
0x1c, 0xe2, 0xaf, 0xb5, 0x1c, 0xba, 0x6f, 0x34, 0x43, 0xea, 0xd8, 0x56, 0x31, 0xe2, 0x97, 0x39, 0xe6, 0x92, 0x3a, 0x7d, 0xa2, 0xbf, 0x6e, 0x5d,
0x9b, 0x43, 0xc9, 0x14, 0xd2, 0x36, 0xa4, 0xa4, 0x17, 0x87, 0x0e, 0x91, 0xa7, 0xa9, 0x6b, 0xae, 0xaa, 0xa8, 0x30, 0xb8, 0x97, 0x13, 0x7a, 0x15,
0x80, 0x20, 0xce, 0x88, 0x76, 0xfc, 0x31, 0x76, 0x71, 0x47, 0xee, 0x3a, 0x7b, 0x20, 0x10, 0xcc, 0xb0, 0x27, 0x0e, 0x1b, 0x10, 0xbd, 0x55, 0xec,
0x73, 0xcf, 0x03, 0xaa, 0xe0, 0x8d, 0x0f, 0x59, 0xfc, 0x60, 0xdf, 0x92, 0x4f, 0xd1, 0xa6, 0x59, 0x29, 0x8c, 0x31, 0x72, 0x07, 0x2f, 0x4f, 0x6e,
0xf0, 0xc8, 0x93, 0xcb, 0xa9, 0x70, 0x61, 0xec, 0x5f, 0x7e, 0x51, 0xd6, 0xd5, 0xc4, 0x50, 0x20, 0x2d, 0x05, 0x29, 0xf8, 0x6c, 0x8d, 0x41, 0xc4,
0x35, 0xb1, 0x45, 0x4b, 0x62, 0xbb, 0xb8, 0x34, 0x83, 0xef, 0xb2, 0x11, 0x0e, 0x9c, 0x74, 0x12, 0x3e, 0xc9, 0xa8, 0x0c, 0x35, 0x43, 0x8a, 0x9d,
0x97, 0xfb, 0xa7, 0xc4, 0x4a, 0x7f, 0xc1, 0x2d, 0x3c, 0x8c, 0x51, 0x96, 0x5b, 0xee, 0x53, 0x18, 0xd9, 0xf1, 0x7c, 0xe2, 0xaf, 0xe5, 0x7c, 0x7a,
0x94, 0x51, 0xe2, 0x47, 0x5c, 0x00, 0xd7, 0xf0, 0x9e, 0x89, 0x34, 0x87, 0x6f, 0xcc, 0x43, 0xae, 0xdb, 0x55, 0xa1, 0x4b, 0x8b, 0x09, 0xeb, 0xd8,
0xd4, 0x7e, 0x5e, 0x92, 0xb1, 0x82, 0xaa, 0x0f, 0xb9, 0x95, 0x97, 0xcb, 0x57, 0xda, 0x8f, 0x64, 0x8f, 0xf2, 0xb0, 0x3c, 0xee, 0x90, 0x77, 0xdd,
0xc1, 0x08, 0x8c, 0x0a, 0x25, 0x3e, 0xc8, 0x7a, 0x36, 0xdf, 0x42, 0x8a, 0x37, 0x76, 0x87, 0xfb, 0xbe, 0x4a, 0xb6, 0x75, 0x03, 0x75, 0xf0, 0x2a,
0x71, 0x17, 0xe6, 0x4d, 0x37, 0x6a, 0xac, 0x7b, 0x32, 0xf1, 0x02, 0x36, 0x92, 0x3c, 0xfe, 0xe1, 0x5c, 0x37, 0x09, 0xc8, 0x55, 0x28, 0xe8, 0x70,
0x4a, 0x07, 0x94, 0x46, 0xdf, 0x46, 0x90, 0xd8, 0x68, 0xb7, 0xf4, 0x7c, 0x37, 0xef, 0x3f, 0x70, 0x71, 0xd9, 0x3b, 0x25, 0x2e, 0x11, 0xc7, 0x71,
0x40, 0x00, 0x8f, 0xf5, 0x2d, 0xaa, 0x2c, 0x00, 0x12, 0x46, 0xf6, 0x61, 0x86, 0x59, 0x0e, 0x5f, 0x1d, 0x24, 0xfe, 0xf9, 0x4f, 0x0a, 0xbb, 0xfe,
0x18, 0xd3, 0x90, 0xf4, 0x75, 0x43, 0x80, 0x84, 0x32, 0x53, 0x74, 0xa9, 0x92, 0x8b, 0x8f, 0x18, 0xa5, 0xaa, 0x68, 0xc3, 0xd4, 0x8f, 0xb8, 0x00,
0xd1, 0x23, 0xbd, 0x6f, 0xb1, 0xfa, 0x18, 0x76, 0x1f, 0xe8, 0x73, 0x8c, 0x6e, 0x3e, 0x7e, 0x24, 0x12, 0x95, 0xa9, 0x3d, 0xbd, 0xa4, 0x93, 0xc5,
0xbf, 0x3e, 0x9c, 0xa3, 0x4c, 0xb9, 0x62, 0xb8, 0x78, 0x51, 0x1c, 0x71, 0x67, 0xef, 0x75, 0x11, 0xb2, 0x50, 0x80, 0xc1, 0x19, 0x1b, 0x8c, 0xbc,
0x86, 0x7e, 0x5f, 0xfa, 0xf9, 0x89, 0x1d, 0x59, 0x58, 0xdd, 0x81, 0x7b, 0x9b, 0x2d, 0xad, 0xbe, 0xe4, 0x95, 0xe4, 0x82, 0xd1, 0xab, 0xee, 0x29,
0xbb, 0x0f, 0xfc, 0x10, 0x8d, 0x61, 0x1d, 0xb7, 0x15, 0x01, 0x54, 0x0c, 0x39, 0x97, 0x8f, 0x92, 0xc5, 0x7e, 0x94, 0x10, 0xe8, 0x8e, 0xbe, 0x05,
0x5e, 0x31, 0x37, 0x83, 0x5f, 0xa6, 0x63, 0x76, 0x08, 0xbb, 0x7a, 0x63, 0x23, 0xb5, 0xda, 0x8e, 0xe9, 0x79, 0x88, 0x10, 0x22, 0x1f, 0x5c, 0xb9,
0x00, 0x53, 0x81, 0x09, 0x8a, 0x67, 0x05, 0x0c, 0x4b, 0xbe, 0x83, 0xc0, 0xd9, 0x10, 0x24, 0x28, 0xed, 0xc1, 0xe8, 0xa6, 0x21, 0xee, 0xda, 0x83,
0x5f, 0x12, 0x43, 0xe9, 0x93, 0x03, 0x2f, 0x22, 0x99, 0x97, 0xce, 0xe8, 0x82, 0x44, 0x43, 0x13, 0x74, 0x69, 0xb0, 0x33, 0xd0, 0xaf, 0x1a, 0x07,
0x4b, 0x7a, 0x56, 0x36, 0x68, 0x14, 0x3b, 0x97, 0x3a, 0xea, 0x2b, 0x63, 0x09, 0x46, 0x42, 0xa8, 0xfb, 0x09, 0x81, 0xe5, 0x91, 0x21, 0xe5, 0xcb,
0x63, 0x00, 0xef, 0x50, 0x49, 0x10, 0x15, 0x6c, 0xc4, 0x00, 0xd0, 0x3e, 0x1b, 0x0e, 0x26, 0x0c, 0x08, 0x99, 0xbb, 0x0c, 0x3a, 0xdc, 0xcf, 0x0e,
0x24, 0xbf, 0x13, 0x85, 0x50, 0xa6, 0x4f, 0xe1, 0x90, 0x84, 0x04, 0xff, 0x9d, 0xc8, 0xc4, 0xee, 0x1a, 0xdc, 0xf5, 0x3d, 0x60, 0x8a, 0xe8, 0x0e,
0x8c, 0x12, 0x8f, 0xdf, 0x3b, 0xda, 0x82, 0x79, 0xc9, 0xa2, 0x1b, 0x04, 0xab, 0xbb, 0xad, 0x49, 0xa0, 0x6d, 0x70, 0x9b, 0x85, 0x29, 0x3c, 0x31,
0xee, 0xc3, 0x16, 0xc8, 0x05, 0x2c, 0xc1, 0x8d, 0x36, 0xb9, 0xad, 0x95, 0xf7, 0xed, 0xa5, 0xed, 0xf6, 0x4c, 0x1f, 0x26, 0x0d, 0x06, 0x8b, 0xe7,
0xb0, 0x76, 0x3d, 0xfc, 0x86, 0xa7, 0xcc, 0x66, 0x70, 0x95, 0x41, 0xcf, 0x0f, 0x0c, 0x4c, 0xbe, 0x23, 0xa0, 0xbf, 0x20, 0x76, 0xd3, 0x23, 0x67,
0xc2, 0x92, 0xa4, 0x42, 0x7f, 0x27, 0xbc, 0x46, 0x84, 0x5d, 0xcd, 0x21, 0x7e, 0x64, 0x32, 0x8b, 0x9d, 0xd0, 0x77, 0x4c, 0x3d, 0xb9, 0xb0, 0x71,
0xb3, 0xa5, 0x73, 0x8f, 0xc8, 0x04, 0xd8, 0x4a, 0x7b, 0x00, 0x46, 0x30, 0x1c, 0x5d, 0x9a, 0xa8, 0xa7, 0x8d, 0xac, 0x3e, 0xbc, 0xe1, 0x27, 0x45,
0xe3, 0x37, 0x11, 0xbc, 0x5e, 0xeb, 0x79, 0x21, 0xca, 0x00, 0x59, 0x31, 0x34, 0xb1, 0x1a, 0x05, 0x60, 0x7b, 0x90, 0xb1, 0x4f, 0x95, 0xa2, 0x19,
0x34, 0x29, 0xd3, 0xdf, 0x4a, 0xe3, 0xf7, 0x4c, 0xf1, 0xf0, 0x6c, 0x62, 0x3f, 0x86, 0xf3, 0x21, 0x0a, 0xfc, 0x6f, 0x55, 0x44, 0xfc, 0x52, 0xde,
0x41, 0xd1, 0x8b, 0x17, 0x11, 0x47, 0xa7, 0x87, 0xce, 0x3a, 0xcc, 0xbc, 0x33, 0x98, 0xc3, 0x1c, 0xca, 0x61, 0xe8, 0x1e, 0x6c, 0xe3, 0x9c, 0xc3,
0xb0, 0xe8, 0x4f, 0x2e, 0x78, 0xbd, 0x7c, 0xda, 0x56, 0x9d, 0x35, 0xa4, 0xb2, 0xdf, 0x6a, 0x93, 0x4b, 0x71, 0x29, 0x67, 0xe7, 0x26, 0x68, 0x89,
0x60, 0xf7, 0x96, 0x25, 0x1e, 0xdf, 0x6f, 0x62, 0xbe, 0xd6, 0xb0, 0x59, 0xda, 0x74, 0x0a, 0xf7, 0x42, 0xcc, 0x3c, 0x2c, 0x78, 0x6a, 0xf4, 0x39,
0x77, 0x64, 0xfc, 0x4a, 0x5a, 0xa2, 0x0a, 0xc7, 0xda, 0xde, 0xa1, 0x14, 0x15, 0x30, 0x29, 0xec, 0x87, 0xca, 0xdc, 0x06, 0x7e, 0x25, 0x07, 0x83,
0x08, 0x0f, 0x94, 0x57, 0x28, 0xe5, 0x36, 0xa8, 0x94, 0xdb, 0x37, 0x2a, 0xd8, 0xc8, 0xfa, 0x21, 0x86, 0x10, 0x29, 0xb4, 0x10, 0xbc, 0x3e, 0xee,
0x25, 0xc4, 0x80, 0xf0, 0xc3, 0x25, 0x30, 0xd4, 0xe6, 0x64, 0x48, 0x47, 0xe3, 0x5c, 0x56, 0x01, 0x94, 0xbe, 0xa6, 0x63, 0x23, 0x8b, 0x5f, 0x9d,
0x6b, 0x50, 0x80, 0xd9, 0x23, 0x1d, 0xff, 0x37, 0xa8, 0x46, 0x43, 0xaf, 0x26, 0xc2, 0x6f, 0x86, 0x06, 0x45, 0x2f, 0x01, 0x4c, 0x1c, 0xea, 0x96,
0x52, 0x4d, 0x7f, 0x2a, 0x8e, 0x8d, 0x10, 0x05, 0xd1, 0x8a, 0x3f, 0x57, 0xdd, 0xb5, 0x1e, 0xbb, 0x28, 0x1a, 0xca, 0x6a, 0xf8, 0x67, 0x82, 0xac,
0x4d, 0x1a, 0xfa, 0x38, 0x35, 0x99, 0x9e, 0xd2, 0x0a, 0x54, 0xc3, 0x8f, 0xa3, 0x41, 0x7b, 0xa0, 0xc1, 0xfe, 0x34, 0x4f, 0x66, 0x85, 0x90, 0xc5,
0xa9, 0xb8, 0x92, 0xd9, 0xa1, 0x2b, 0x3e, 0x2b, 0x98, 0xb6, 0xea, 0x8e, 0x05, 0x1b, 0xc4, 0x86, 0xde, 0x51, 0xf1, 0x2b, 0x9c, 0x89, 0x46, 0x3c,
0xde, 0x14, 0x1c, 0xc7, 0x0e, 0x53, 0x3f, 0xc2, 0xb5, 0x46, 0x4a, 0xfe, 0xd6, 0xf7, 0x26, 0xe5, 0xe0, 0xd7, 0x93, 0xac, 0xa3, 0x9c, 0xdb, 0xb0,
0xe2, 0x5b, 0x55, 0x9b, 0x0d, 0x38, 0xeb, 0x6a, 0xdf, 0x84, 0xa6, 0xc8, 0x72, 0x6e, 0x5f, 0xad, 0x9c, 0x08, 0x7b, 0xc2, 0x3f, 0x2e, 0x81, 0xa7,
0x65, 0x38, 0xa8, 0xd5, 0xc2, 0x07, 0x7d, 0xbd, 0x77, 0x97, 0xf1, 0x3f, 0xb6, 0xa0, 0x42, 0xd6, 0xdc, 0x80, 0x02, 0xcc, 0x21, 0xb1, 0x82, 0xbf,
0x1d, 0xa4, 0x79, 0x7e, 0xf1, 0xbf, 0xb3, 0x48, 0x33, 0x70, 0x39, 0x18, 0x4b, 0x45, 0x06, 0x5a, 0x4f, 0x45, 0xf4, 0x35, 0x2f, 0x61, 0x45, 0xd1,
0x13, 0x1c, 0x29, 0x06, 0x15, 0xf3, 0x64, 0x4b, 0x38, 0x3b, 0xd5, 0x10, 0x8a, 0x3f, 0x5b, 0x5d, 0x06, 0x7a, 0x5f, 0x75, 0x31, 0x6f, 0xea, 0xc4,
0xce, 0xf2, 0xa9, 0x12, 0x30, 0x9d, 0xc8, 0xfd, 0xf8, 0xdd, 0xd7, 0x3f, 0xbc, 0xd1, 0xc7, 0x75, 0x3c, 0x29, 0xf7, 0xe8, 0x65, 0xa5, 0x1d, 0x9c,
0xa7, 0x60, 0x69, 0x7c, 0x02, 0x5f, 0xc9, 0x13, 0xf8, 0xf1, 0xf5, 0xcf, 0xdb, 0x95, 0xfb, 0xaf, 0x0c, 0xb5, 0x93, 0xc7, 0xbb, 0xef, 0xe2, 0x7e,
0xdf, 0x24, 0x73, 0x13, 0x31, 0xed, 0xf4, 0xc4, 0x2c, 0x0d, 0x6f, 0x55, 0xe3, 0xe5, 0x7f, 0x09, 0xae, 0xe2, 0x59, 0x1b, 0xee, 0x3a, 0x3e, 0xb4,
0x4b, 0xd3, 0x17, 0x1e, 0x30, 0xcf, 0xa4, 0xb9, 0x1f, 0xa1, 0xe4, 0x67, 0x8a, 0xd7, 0xd4, 0x2a, 0x1c, 0x63, 0x3b, 0xc3, 0x67, 0xa4, 0x03, 0x57,
0xa0, 0x4d, 0x0a, 0x8f, 0xcc, 0x8e, 0x0e, 0x06, 0xe2, 0x9e, 0x5c, 0x80, 0xca, 0xf1, 0xff, 0x26, 0x08, 0xf5, 0xf1, 0x25, 0xfc, 0x8e, 0x22, 0x0b,
0x1d, 0x74, 0xa4, 0x09, 0x09, 0xf2, 0xc2, 0x01, 0xf3, 0x27, 0xd6, 0x99, 0x57, 0x80, 0x79, 0xc1, 0x81, 0x6c, 0xd0, 0xb6, 0x48, 0x36, 0xbf, 0xf3,
0xf9, 0x93, 0xce, 0x36, 0xc1, 0x2b, 0xd6, 0x9e, 0xbd, 0xcc, 0x04, 0x8b, 0x13, 0x03, 0xe1, 0xe4, 0xa3, 0xae, 0x00, 0xef, 0xa9, 0xc2, 0x8f, 0xdf,
0x8b, 0x58, 0xcb, 0xe7, 0x39, 0xe0, 0x61, 0x2f, 0xb0, 0x62, 0xe7, 0xe6, 0x7d, 0xf5, 0x73, 0x06, 0x16, 0xe2, 0x87, 0xf0, 0x95, 0x3e, 0x84, 0x87,
0x2f, 0x80, 0xc7, 0x68, 0x01, 0x2c, 0x53, 0x6f, 0xc7, 0x39, 0xba, 0x76, 0xaf, 0x7e, 0xfe, 0x3a, 0x5d, 0x18, 0xcb, 0x59, 0xb7, 0x53, 0xa6, 0x59,
0xf6, 0xbc, 0x21, 0x8b, 0x5e, 0x05, 0xc6, 0x5d, 0xa8, 0x1f, 0x42, 0x52, 0x78, 0x75, 0x60, 0x96, 0xbe, 0xa3, 0x82, 0xfb, 0x48, 0xda, 0xfb, 0x11,
0x4b, 0x90, 0xef, 0x74, 0x88, 0x49, 0x94, 0xb9, 0x30, 0x96, 0x20, 0x7f, 0x4a, 0x7e, 0x06, 0xda, 0xa4, 0x70, 0xdf, 0xee, 0xf5, 0x70, 0x54, 0xef,
0x83, 0x47, 0x7d, 0x8e, 0xbb, 0xe3, 0x96, 0x90, 0x9e, 0x19, 0xe9, 0x39, 0xcb, 0x3e, 0x38, 0xd1, 0x4a, 0x96, 0xd0, 0x20, 0xaf, 0x87, 0x60, 0x8f,
0x6c, 0x05, 0xdb, 0xd9, 0xed, 0xec, 0x01, 0xfe, 0x95, 0x85, 0xa5, 0xb9, 0x58, 0x77, 0xec, 0x91, 0x4d, 0x4c, 0xe1, 0xbb, 0xef, 0xbe, 0x7d, 0xda,
0xfb, 0xc5, 0xe8, 0xae, 0xc5, 0x39, 0xec, 0xb9, 0xe3, 0x64, 0x96, 0x71, 0x14, 0x8f, 0x8b, 0x78, 0xdb, 0x2b, 0x7a, 0xe0, 0xa3, 0xde, 0xbe, 0xc6,
0xc2, 0xce, 0x8d, 0x71, 0x66, 0x9f, 0xfd, 0xd6, 0x69, 0x1a, 0xb3, 0x61, 0xcf, 0xd8, 0x13, 0x20, 0x60, 0xbc, 0x30, 0x9a, 0xad, 0xbc, 0x83, 0x02,
0xbd, 0x7f, 0xfd, 0x18, 0x9f, 0xcc, 0x63, 0x14, 0x7a, 0xbb, 0x9a, 0x75, 0x5d, 0xa9, 0xfb, 0x5f, 0xf1, 0x46, 0x2f, 0x67, 0xe3, 0xee, 0x34, 0xcb,
0xf7, 0xff, 0x11, 0x6b, 0x32, 0x09, 0x47, 0xf5, 0x18, 0x11, 0x2a, 0x2d, 0x90, 0x5d, 0x93, 0xd4, 0x3b, 0x13, 0xc2, 0x19, 0x6d, 0x26, 0x8d, 0x14,
0x11, 0x31, 0x29, 0x28, 0xf3, 0xd5, 0x62, 0xa9, 0x43, 0x6b, 0xcc, 0x1e, 0x48, 0x20, 0x61, 0x7f, 0x50, 0x10, 0xee, 0x84, 0x05, 0xa4, 0x87, 0x86,
0x09, 0xad, 0xb3, 0x22, 0x4d, 0xfb, 0xfa, 0xb3, 0x75, 0xa1, 0x99, 0xbc, 0x66, 0x01, 0x9b, 0xc4, 0x66, 0x7e, 0x33, 0xbf, 0x87, 0x9f, 0xf2, 0x90,
0x28, 0xd8, 0x8b, 0x22, 0x92, 0x9b, 0xe1, 0x18, 0xcb, 0x7b, 0x57, 0xdc, 0x09, 0xf0, 0xfe, 0xb3, 0x03, 0x9e, 0x5c, 0x00, 0x1c, 0x31, 0xc0, 0x49,
0x44, 0xdd, 0xf2, 0xa0, 0x6e, 0x01, 0x2a, 0x45, 0xa0, 0xe2, 0x62, 0x29, 0x35, 0xeb, 0x90, 0x9f, 0x59, 0xa3, 0xdc, 0x2e, 0xff, 0xad, 0xa7, 0x6d,
0xe1, 0x45, 0xf4, 0x39, 0xfa, 0x42, 0xfa, 0x3f, 0x00, 0x33, 0xfc, 0x14, 0xcc, 0x88, 0xf3, 0x0f, 0x1c, 0x1c, 0xe0, 0x13, 0x8c, 0x9c, 0x46, 0xef,
0xf6, 0xa1, 0x5e, 0x00, 0x00 0xbd, 0xf3, 0x5e, 0x4b, 0xd8, 0xe7, 0x6d, 0x3e, 0xe1, 0x4c, 0x23, 0x27,
0x43, 0xad, 0x2d, 0x28, 0xa6, 0x06, 0x65, 0xc1, 0x6a, 0x2c, 0x7c, 0x74,
0x15, 0xeb, 0x9b, 0xe8, 0x4a, 0x3b, 0x5c, 0x75, 0xae, 0xa5, 0xdb, 0x17,
0xcd, 0xc9, 0xbb, 0xb4, 0x03, 0x38, 0x32, 0xb9, 0xb8, 0x8f, 0xd1, 0xfc,
0x57, 0xf9, 0x19, 0xee, 0x86, 0x0f, 0x77, 0x03, 0x70, 0x29, 0x02, 0x93,
0x1a, 0xcb, 0x0a, 0x8f, 0x07, 0x05, 0xf6, 0x6f, 0x3f, 0xfc, 0x01, 0x35,
0x65, 0x9f, 0x7f, 0x0d, 0x62, 0x00, 0x00
}; };
File diff suppressed because it is too large Load Diff
+260
View File
@@ -0,0 +1,260 @@
#include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson
#if defined(ARDUINOJSON_VERSION)
#if !(ARDUINOJSON_VERSION_MAJOR == 6 and ARDUINOJSON_VERSION_MINOR >= 8)
#error "Install ArduinoJson v6.8.x or higher"
#endif
#endif
char * listStateJSONfull() {
const size_t bufferSize = JSON_ARRAY_SIZE(12) + JSON_OBJECT_SIZE(19) + 250;
DynamicJsonDocument jsonBuffer(bufferSize);
JsonObject root = jsonBuffer.to<JsonObject>();
root["segment"] = State.segment;
root["start"] = segState.start;
root["stop"] = segState.stop;
root["mode"] = (uint8_t) State.mode;
root["fx_mode"] = segState.mode[State.segment];
root["speed"] = segState.speed[State.segment];
root["brightness"] = State.brightness;
JsonArray color = root.createNestedArray("color");
color.add(main_color.white);
color.add(main_color.red);
color.add(main_color.green);
color.add(main_color.blue);
color.add(back_color.white);
color.add(back_color.red);
color.add(back_color.green);
color.add(back_color.blue);
color.add(xtra_color.white);
color.add(xtra_color.red);
color.add(xtra_color.green);
color.add(xtra_color.blue);
root["ws_fxopt"] = segState.options;
root["hostname"] = HOSTNAME;
#if defined(ENABLE_MQTT)
root["mqtt_host"] = mqtt_host;
root["mqtt_port"] = mqtt_port;
root["mqtt_user"] = mqtt_user;
root["mqtt_pass"] = mqtt_pass;
#endif
root["ws_seg"] = Config.segments;
root["ws_cnt"] = Config.stripSize;
root["ws_rgbo"] = Config.RGBOrder;
root["ws_pin"] = Config.pin;
root["ws_trans"] = Config.transEffect;
uint16_t msg_len = measureJson(root) + 1;
char * buffer = (char *) malloc(msg_len);
serializeJson(root, buffer, msg_len);
jsonBuffer.clear();
return buffer;
}
char * listStateJSON() {
const size_t bufferSize = JSON_OBJECT_SIZE(3) + 25;
DynamicJsonDocument jsonBuffer(bufferSize);
JsonObject root = jsonBuffer.to<JsonObject>();
root["segment"] = State.segment;
root["mode"] = (uint8_t) State.mode;
root["brightness"] = State.brightness;
uint16_t msg_len = measureJson(root) + 1;
char * buffer = (char *) malloc(msg_len);
serializeJson(root, buffer, msg_len);
jsonBuffer.clear();
return buffer;
}
char * listSegmentStateJSON(uint8_t _seg) {
const size_t bufferSize = JSON_ARRAY_SIZE(12) + JSON_OBJECT_SIZE(6) + 100;
DynamicJsonDocument jsonBuffer(bufferSize);
JsonObject root = jsonBuffer.to<JsonObject>();
root["start"] = strip->getSegment(_seg)->start;
root["stop"] = strip->getSegment(_seg)->stop;
root["fx_mode"] = segState.mode[_seg];
root["speed"] = segState.speed[_seg];
JsonArray color = root.createNestedArray("color");
//color.add((strip->getColors(_seg)[0] >> 24) & 0xFF);
color.add((segState.colors[_seg][0] >> 24) & 0xFF);
color.add((segState.colors[_seg][0] >> 16) & 0xFF);
color.add((segState.colors[_seg][0] >> 8) & 0xFF);
color.add((segState.colors[_seg][0]) & 0xFF);
color.add((segState.colors[_seg][1] >> 24) & 0xFF);
color.add((segState.colors[_seg][1] >> 16) & 0xFF);
color.add((segState.colors[_seg][1] >> 8) & 0xFF);
color.add((segState.colors[_seg][1]) & 0xFF);
color.add((segState.colors[_seg][2] >> 24) & 0xFF);
color.add((segState.colors[_seg][2] >> 16) & 0xFF);
color.add((segState.colors[_seg][2] >> 8) & 0xFF);
color.add((segState.colors[_seg][2]) & 0xFF);
root["ws_fxopt"] = strip->getOptions(_seg);
uint16_t msg_len = measureJson(root) + 1;
char * buffer = (char *) malloc(msg_len);
serializeJson(root, buffer, msg_len);
jsonBuffer.clear();
return buffer;
}
void getStateJSON() {
char * buffer = listStateJSONfull();
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send ( 200, "application/json", buffer);
free (buffer);
}
char * listConfigJSON() {
#if defined(ENABLE_MQTT)
const size_t bufferSize = JSON_OBJECT_SIZE(10) + 150;
#else
const size_t bufferSize = JSON_OBJECT_SIZE(6) + 100;
#endif
DynamicJsonDocument jsonBuffer(bufferSize);
JsonObject root = jsonBuffer.to<JsonObject>();
root["hostname"] = HOSTNAME;
#if defined(ENABLE_MQTT)
root["mqtt_host"] = mqtt_host;
root["mqtt_port"] = mqtt_port;
root["mqtt_user"] = mqtt_user;
root["mqtt_pass"] = mqtt_pass;
#endif
root["ws_seg"] = Config.segments;
root["ws_cnt"] = Config.stripSize;
root["ws_rgbo"] = Config.RGBOrder;
root["ws_pin"] = Config.pin;
root["ws_trans"] = Config.transEffect;
uint16_t msg_len = measureJson(root) + 1;
char * buffer = (char *) malloc(msg_len);
serializeJson(root, buffer, msg_len);
jsonBuffer.clear();
return buffer;
}
void getConfigJSON() {
char * buffer = listConfigJSON();
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send ( 200, "application/json", buffer);
free (buffer);
}
char * listModesJSON() {
const size_t bufferSize = JSON_ARRAY_SIZE(strip->getModeCount() + 1) + (strip->getModeCount() + 1)*JSON_OBJECT_SIZE(2) + 2000;
DynamicJsonDocument jsonBuffer(bufferSize);
JsonArray root = jsonBuffer.to<JsonArray>();
JsonObject objectoff = root.createNestedObject();
objectoff["mode"] = "off";
objectoff["name"] = "OFF";
for (uint8_t i = 0; i < strip->getModeCount(); i++) {
JsonObject object = root.createNestedObject();
object["mode"] = i;
object["name"] = strip->getModeName(i);
}
uint16_t msg_len = measureJson(root) + 1;
char * buffer = (char *) malloc(msg_len);
serializeJson(root, buffer, msg_len);
jsonBuffer.clear();
return buffer;
}
void getModesJSON() {
char * buffer = listModesJSON();
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send ( 200, "application/json", buffer);
free (buffer);
}
char * listESPStateJSON() {
const size_t bufferSize = JSON_OBJECT_SIZE(31) + 1500;
DynamicJsonDocument jsonBuffer(bufferSize);
JsonObject root = jsonBuffer.to<JsonObject>();
root["HOSTNAME"] = HOSTNAME;
root["version"] = SKETCH_VERSION;
root["heap"] = ESP.getFreeHeap();
root["sketch_size"] = ESP.getSketchSize();
root["free_sketch_space"] = ESP.getFreeSketchSpace();
root["flash_chip_size"] = ESP.getFlashChipSize();
root["flash_chip_real_size"] = ESP.getFlashChipRealSize();
root["flash_chip_speed"] = ESP.getFlashChipSpeed();
root["sdk_version"] = ESP.getSdkVersion();
root["core_version"] = ESP.getCoreVersion();
root["cpu_freq"] = ESP.getCpuFreqMHz();
root["chip_id"] = ESP.getFlashChipId();
#if defined(USE_WS2812FX_DMA)
#if USE_WS2812FX_DMA == 0
root["animation_lib"] = "WS2812FX_DMA";
#endif
#if USE_WS2812FX_DMA == 1
root["animation_lib"] = "WS2812FX_UART1";
#endif
#if USE_WS2812FX_DMA == 2
root["animation_lib"] = "WS2812FX_UART2";
#endif
#else
root["animation_lib"] = "WS2812FX";
#endif
root["ws2812_pin"] = Config.pin;
root["led_count"] = Config.stripSize;
root["rgb_order"] = Config.RGBOrder;
if (strstr(Config.RGBOrder, "W") != NULL) {
root["rgbw_mode"] = "ON";
} else {
root["rgbw_mode"] = "OFF";
}
#if defined(ENABLE_BUTTON)
root["button_mode"] = "ON";
root["button_pin"] = ENABLE_BUTTON;
#else
root["button_mode"] = "OFF";
#endif
#if defined(ENABLE_BUTTON_GY33)
root["button_gy33"] = "ON";
root["gy33_pin"] = ENABLE_BUTTON_GY33;
#else
root["button_gy33"] = "OFF";
#endif
#if defined(ENABLE_REMOTE)
root["ir_remote"] = "ON";
root["tsop_ir_pin"] = ENABLE_REMOTE;
#else
root["ir_remote"] = "OFF";
#endif
#if defined(ENABLE_MQTT)
#if ENABLE_MQTT == 0
root["mqtt"] = "MQTT";
#endif
#if ENABLE_MQTT == 1
root["mqtt"] = "AMQTT";
#endif
#else
root["mqtt"] = "OFF";
#endif
#if defined(ENABLE_HOMEASSISTANT)
root["home_assistant"] = "ON";
#else
root["home_assistant"] = "OFF";
#endif
#if defined(ENABLE_OTA)
#if ENABLE_OTA == 0
root["ota"] = "ARDUINO";
#endif
#if ENABLE_OTA == 1
root["ota"] = "HTTP";
#endif
#else
root["ota"] = "OFF";
#endif
#if defined(ENABLE_STATE_SAVE)
root["state_save"] = "SPIFFS";
#else
root["state_save"] = "OFF";
#endif
uint16_t msg_len = measureJson(root) + 1;
char * buffer = (char *) malloc(msg_len);
serializeJson(root, buffer, msg_len);
jsonBuffer.clear();
return buffer;
}
void getESPStateJSON() {
char * buffer = listESPStateJSON();
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "application/json", buffer);
free (buffer);
}
@@ -1,59 +1,64 @@
// Prototypes
uint16_t convertSpeed(uint8_t _mcl_speed);
uint32_t trans(uint32_t _newcolor, uint32_t _oldcolor, uint8_t _level, uint8_t _steps);
// End Prototypes
/* /*
Example of adding the example: https://github.com/kitesurfer1404/WS2812FX/blob/master/examples/ws2812fx_custom_FastLED/ws2812fx_custom_FastLED.ino Example of adding the example: https://github.com/kitesurfer1404/WS2812FX/blob/master/examples/ws2812fx_custom_FastLED/ws2812fx_custom_FastLED.ino
as a custom effect as a custom effect
More info on how to create custom aniamtions for WS2812FX: https://github.com/kitesurfer1404/WS2812FX/blob/master/extras/WS2812FX%20Users%20Guide.md#custom-effects More info on how to create custom aniamtions for WS2812FX: https://github.com/kitesurfer1404/WS2812FX/blob/master/extras/WS2812FX%20Users%20Guide.md#custom-effects
*/ */
uint16_t handleSegmentOFF(void) {
WS2812FX::Segment* _seg = strip->getSegment();
return _seg->speed;
}
// *************************************************************************** // ***************************************************************************
// Functions and variables for automatic cycling // Function for automatic cycling
// *************************************************************************** // ***************************************************************************
void handleAutoPlay(uint8_t _seg) {
void handleAutoPlay() { //WS2812FX::Segment* _seg = strip->getSegment();
if (autoDelay <= millis()) { if (autoDelay[_seg] <= millis()) {
hex_colors[0] = autoParams[autoCount][0]; uint32_t _hex_colors[3] = {};
hex_colors[1] = autoParams[autoCount][1]; //if (_seg ==
hex_colors[2] = autoParams[autoCount][2]; _hex_colors[0] = autoParams[autoCount[_seg]][0];
strip->setColors(selected_segment, hex_colors); _hex_colors[1] = autoParams[autoCount[_seg]][1];
strip->setSpeed(selected_segment, convertSpeed((uint8_t)autoParams[autoCount][3])); _hex_colors[2] = autoParams[autoCount[_seg]][2];
strip->setMode(selected_segment, (uint8_t)autoParams[autoCount][4]); //}
strip->trigger(); strip->setColors(_seg, _hex_colors);
autoDelay = millis() + (uint32_t)autoParams[autoCount][5]; strip->setSpeed(_seg, convertSpeed((uint16_t)autoParams[autoCount[_seg]][3]));
DBG_OUTPUT_PORT.print("autoTick "); strip->setMode(_seg, (uint8_t)autoParams[autoCount[_seg]][4]);
DBG_OUTPUT_PORT.printf("autoTick[%d]: {0x%08x, 0x%08x, 0x%08x, %d, %d, %d}\r\n", autoCount, hex_colors[0], hex_colors[1], hex_colors[2], autoParams[autoCount][3], autoParams[autoCount][4], autoParams[autoCount][5]); //strip->trigger();
autoDelay[_seg] = millis() + (unsigned long)autoParams[autoCount[_seg]][5];
autoCount++; DBG_OUTPUT_PORT.printf("autoTick[%d][%d]: {0x%08x, 0x%08x, 0x%08x, %d, %d, %d}\r\n", _seg, autoCount[_seg], autoParams[autoCount[_seg]][0], autoParams[autoCount[_seg]][1], autoParams[autoCount[_seg]][2], autoParams[autoCount[_seg]][3], autoParams[autoCount[_seg]][4], autoParams[autoCount[_seg]][5]);
if (autoCount >= (sizeof(autoParams) / sizeof(autoParams[0]))) autoCount = 0; autoCount[_seg]++;
if (autoCount[_seg] >= (sizeof(autoParams) / sizeof(autoParams[0]))) autoCount[_seg] = 0;
} }
} }
void handleAuto() { uint16_t handleAuto() {
// Dummy function WS2812FX::Segment* _seg = strip->getSegment();
return _seg->speed;
} }
void handleCustomWS() { uint16_t handleCustomWS(void) {
// Dummy function WS2812FX::Segment* _seg = strip->getSegment();
return _seg->speed;
} }
#if defined(CUSTOM_WS2812FX_ANIMATIONS) #if defined(CUSTOM_WS2812FX_ANIMATIONS)
// *************************************************************************** // ***************************************************************************
// TV mode // TV mode to be reviewed
// *************************************************************************** // ***************************************************************************
uint16_t darkTime[10] = {250,250,250,250,250,250,250,250,250,250};
uint8_t dipInterval = 10; uint8_t dipInterval[10] = {10,10,10,10,10,10,10,10,10,10};
uint16_t darkTime = 250; unsigned long dipStartTime[10] = {};
unsigned long currentDipTime; uint8_t ledState[10] = {LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW};
unsigned long dipStartTime; unsigned long previousMillis[10]= {0,0,0,0,0,0,0,0,0,0};
unsigned long currentMillis; uint16_t interv[10] = {2000,2000,2000,2000,2000,2000,2000,2000,2000,2000};
uint8_t ledState = LOW; uint8_t twitch[10]= {50,50,50,50,50,50,50,50,50,50};
long previousMillis = 0; uint8_t dipCount[10] = {0,0,0,0,0,0,0,0,0,0};
uint16_t led = 5; bool timeToDip[10] = {false,false,false,false,false,false,false,false,false,false};
uint16_t interv = 2000;
uint8_t twitch = 50;
uint8_t dipCount = 0;
boolean timeToDip = false;
void hsb2rgbAN1(uint16_t index, uint8_t sat, uint8_t bright, uint16_t led) { void hsb2rgbAN1(uint16_t index, uint8_t sat, uint8_t bright, uint16_t led) {
@@ -66,63 +71,64 @@ void hsb2rgbAN1(uint16_t index, uint8_t sat, uint8_t bright, uint16_t led) {
} }
void updateLed (uint16_t led, uint8_t brightness) { uint16_t handleTV(void) {
ledstates[led] = brightness; WS2812FX::Segment* _seg = strip->getSegment();
for (uint16_t i=0; i<WS2812FXStripSettings.stripSize; i++) { uint8_t _seg_num = strip->getSegmentIndex();
uint16_t index = (i%3 == 0) ? 400 : random(0,767); if (timeToDip[_seg_num] == false) {
hsb2rgbAN1(index, 200, ledstates[i], i); if((millis() - previousMillis[_seg_num]) > interv[_seg_num]) {
} DBG_OUTPUT_PORT.println("Segment:");
//strip->show(); DBG_OUTPUT_PORT.println(_seg_num);
} previousMillis[_seg_num] = millis();
// See: http://forum.mysensors.org/topic/85/phoneytv-for-vera-is-here/13
void handleTV() {
if (timeToDip == false) {
currentMillis = millis();
if(currentMillis-previousMillis > interv) {
previousMillis = currentMillis;
//interv = random(750,4001);//Adjusts the interval for more/less frequent random light changes //interv = random(750,4001);//Adjusts the interval for more/less frequent random light changes
interv = random(1000-(ws2812fx_speed*2),5001-(ws2812fx_speed*8)); interv[_seg_num] = random(800-(512 - (_seg->speed/64)),6001-(2731 - (_seg->speed/24)));
twitch = random(40,100);// Twitch provides motion effect but can be a bit much if too high twitch[_seg_num] = random(40,100);// Twitch provides motion effect but can be a bit much if too high
dipCount = dipCount++; dipCount[_seg_num]++;
} }
if(currentMillis-previousMillis<twitch) { if((millis() - previousMillis[_seg_num]) < twitch[_seg_num]) {
led=random(0, WS2812FXStripSettings.stripSize - 1); uint16_t led=random(_seg->start, _seg->stop);
ledState = ledState == LOW ? HIGH: LOW; // if the LED is off turn it on and vice-versa: ledState[_seg_num] = ledState[_seg_num] == LOW ? HIGH : LOW; // if the LED is off turn it on and vice-versa:
updateLed(led, (ledState) ? 255 : 0); ledstates[led] = ((ledState[_seg_num]) ? 255 : 0);
if (dipCount > dipInterval) { for (uint16_t j=_seg->start; j<=_seg->stop; j++) {
DBG_OUTPUT_PORT.println("dip"); uint16_t index = (j%3 == 0) ? 400 : random(0,767);
timeToDip = true; hsb2rgbAN1(index, 200, ledstates[j], j);
dipCount = 0; }
dipStartTime = millis(); if (dipCount[_seg_num] > dipInterval[_seg_num]) {
darkTime = random(50,150); timeToDip[_seg_num] = true;
dipInterval = random(5,250);// cycles of flicker dipCount[_seg_num] = 0;
dipStartTime[_seg_num] = millis();
darkTime[_seg_num] = random(50,150);
dipInterval[_seg_num] = random(5,250);// cycles of flicker
} }
} }
} else { } else {
DBG_OUTPUT_PORT.println("Dip Time"); DBG_OUTPUT_PORT.println("Dip Time");
currentDipTime = millis(); if (millis() - dipStartTime[_seg_num] < darkTime[_seg_num]) {
if (currentDipTime - dipStartTime < darkTime) { for (uint16_t i=(_seg->start + 3); i<= _seg->stop; i++) {
for (uint16_t i=3; i<WS2812FXStripSettings.stripSize; i++) { ledstates[i] = 0;
updateLed(i, 0); for (uint16_t j=_seg->start; j<=_seg->stop; j++) {
uint16_t index = (j%3 == 0) ? 400 : random(0,767);
hsb2rgbAN1(index, 200, ledstates[j], j);
}
} }
} else { } else {
timeToDip = false; timeToDip[_seg_num] = false;
} }
} }
return _seg->speed;
} }
// ***************************************************************************
void handleE131(){ // TV mode
if (!e131->isEmpty()) // ***************************************************************************
{ uint16_t handleE131(void) {
WS2812FX::Segment* _seg = strip->getSegment();
if (!e131->isEmpty()) {
e131_packet_t packet; e131_packet_t packet;
e131->pull(&packet); // Pull packet from ring buffer e131->pull(&packet); // Pull packet from ring buffer
uint16_t universe = htons(packet.universe); uint16_t universe = htons(packet.universe);
uint8_t *data = packet.property_values + 1; uint8_t *data = packet.property_values + 1;
if (universe < START_UNIVERSE || universe > END_UNIVERSE) return; //async will take care about filling the buffer if (universe < START_UNIVERSE || universe > END_UNIVERSE) return _seg->speed; //async will take care about filling the buffer
// Serial.printf("Universe %u / %u Channels | Packet#: %u / Errors: %u / CH1: %u\n", // Serial.printf("Universe %u / %u Channels | Packet#: %u / Errors: %u / CH1: %u\n",
// htons(packet.universe), // The Universe for this packet // htons(packet.universe), // The Universe for this packet
@@ -133,13 +139,14 @@ void handleE131(){
/* #if defined(RGBW) /* #if defined(RGBW)
uint16_t multipacketOffset = (universe - START_UNIVERSE) * 128; //if more than 128 LEDs * 4 colors = 512 channels, client will send in next higher universe uint16_t multipacketOffset = (universe - START_UNIVERSE) * 128; //if more than 128 LEDs * 4 colors = 512 channels, client will send in next higher universe
if (NUMLEDS <= multipacketOffset) return; if (NUMLEDS <= multipacketOffset) return;
uint16_t len = (128 + multipacketOffset > WS2812FXStripSettings.stripSize) ? (WS2812FXStripSettings.stripSize - multipacketOffset) : 128; uint16_t len = (128 + multipacketOffset > Config.stripSize) ? (Config.stripSize - multipacketOffset) : 128;
#else*/ #else*/
uint16_t multipacketOffset = (universe - START_UNIVERSE) * 170; //if more than 170 LEDs * 3 colors = 510 channels, client will send in next higher universe uint16_t multipacketOffset = (universe - START_UNIVERSE) * 170; //if more than 170 LEDs * 3 colors = 510 channels, client will send in next higher universe
if (WS2812FXStripSettings.stripSize <= multipacketOffset) return; if (Config.stripSize <= multipacketOffset) return _seg->speed;
uint16_t len = (170 + multipacketOffset > WS2812FXStripSettings.stripSize) ? (WS2812FXStripSettings.stripSize - multipacketOffset) : 170; uint16_t len = (170 + multipacketOffset > Config.stripSize) ? (Config.stripSize - multipacketOffset) : 170;
/* #endif */ /* #endif */
for (uint16_t i = 0; i < len; i++){ for (uint16_t i = 0; i < len; i++){
if ((i >= _seg->start) && (i <= _seg->stop)) {
uint16_t j = i * 3; uint16_t j = i * 3;
/* #if defined(RGBW) /* #if defined(RGBW)
strip->setPixelColor(i + multipacketOffset, data[j], data[j + 1], data[j + 2], data[j + 3]); strip->setPixelColor(i + multipacketOffset, data[j], data[j + 1], data[j + 2], data[j + 3]);
@@ -149,13 +156,14 @@ void handleE131(){
} }
} }
} }
return _seg->speed;
}
#include <FastLED.h> //https://github.com/FastLED/FastLED
/* /*
* paste in the Fire2012 code with a small edit at the end which uses the * paste in the Fire2012 code with a small edit at the end which uses the
* setPixelColor() function to copy the color data to the ws2812fx instance. * setPixelColor() function to copy the color data to the ws2812fx instance.
*/ */
#include <FastLED.h> //https://github.com/FastLED/FastLED
// Fire2012 by Mark Kriegsman, July 2012 // Fire2012 by Mark Kriegsman, July 2012
// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY // as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY
//// ////
@@ -194,82 +202,52 @@ void handleE131(){
// Default 120, suggested range 50-200. // Default 120, suggested range 50-200.
#define SPARKING 120 #define SPARKING 120
bool gReverseDirection = false; uint16_t handleFire2012(void) {
void Fire2012() {
// Array of temperature readings at each simulation cell // Array of temperature readings at each simulation cell
WS2812FX::Segment* _seg = strip->getSegment();
// Step 1. Cool down every cell a little // Step 1. Cool down every cell a little
for( uint16_t i = 0; i < WS2812FXStripSettings.stripSize; i++) { for( uint16_t i = _seg->start; i <= _seg->stop; i++) {
ledstates[i] = qsub8( ledstates[i], random8(0, ((COOLING * 10) / WS2812FXStripSettings.stripSize) + 2)); ledstates[i] = qsub8(ledstates[i], random8(0, ((COOLING * 10) / (_seg->stop - _seg->start)+1) + 2));
} }
// Step 2. Heat from each cell drifts 'up' and diffuses a little // Step 2. Heat from each cell drifts 'up' and diffuses a little
for( uint16_t k= WS2812FXStripSettings.stripSize - 1; k >= 2; k--) { for( uint16_t k= _seg->stop; k >= (_seg->start + 2); k--) {
ledstates[k] = (ledstates[k - 1] + ledstates[k - 2] + ledstates[k - 2]) / 3; ledstates[k] = (ledstates[k - 1] + ledstates[k - 2] + ledstates[k - 2]) / 3;
} }
// Step 3. Randomly ignite new 'sparks' of heat near the bottom // Step 3. Randomly ignite new 'sparks' of heat near the bottom
if( random8() < SPARKING ) { if( random8() < SPARKING ) {
uint8_t y = random8(7); uint8_t y = random8(7) + _seg->start;
ledstates[y] = qadd8(ledstates[y], random8(160,255) ); ledstates[y] = qadd8(ledstates[y], random8(160,255) );
} }
// Step 4. Map from heat cells to LED colors // Step 4. Map from heat cells to LED colors
for( uint16_t j = 0; j < WS2812FXStripSettings.stripSize; j++) { for( uint16_t j = _seg->start; j <= _seg->stop; j++) {
CRGB color = HeatColor(ledstates[j]); CRGB color = HeatColor(ledstates[j]);
uint16_t pixelnumber; uint16_t pixel;
if( gReverseDirection ) { if ((_seg->options & 128) > 0) {
pixelnumber = (WS2812FXStripSettings.stripSize - 1) - j; pixel = _seg->stop + (_seg->start - j);
} else { } else {
pixelnumber = j; pixel = j;
} }
strip->setPixelColor(pixelnumber, color.red, color.green, color.blue, 0); strip->setPixelColor(pixel, color.red, color.green, color.blue, 0);
} }
return _seg->speed;
} }
void Gradient() { uint16_t handleGradient() {
for( uint16_t j = 0; j < WS2812FXStripSettings.stripSize; j++) { WS2812FX::Segment* _seg = strip->getSegment();
uint16_t pixelnumber; for(uint16_t j = 0; j <= (_seg->stop - _seg->start); j++) {
uint32_t color; uint16_t pixel;
if( gReverseDirection ) { if ((_seg->options & 128) > 0) {
pixelnumber = (WS2812FXStripSettings.stripSize - 1) - j; pixel = _seg->stop - j;
} else { } else {
pixelnumber = j; pixel = _seg->start + j;
} }
color = trans(strip->getColors(selected_segment)[1], strip->getColors(selected_segment)[0], (j*255)/(WS2812FXStripSettings.stripSize - 1)); uint32_t color = trans(_seg->colors[1], _seg->colors[0], j, (_seg->stop - _seg->start));
strip->setPixelColor(pixelnumber, ((color >> 16) & 0xFF), ((color >> 8) & 0xFF), ((color >> 0) & 0xFF), ((color >> 24) & 0xFF)); strip->setPixelColor(pixel, ((color >> 16) & 0xFF), ((color >> 8) & 0xFF), ((color >> 0) & 0xFF), ((color >> 24) & 0xFF));
} }
} return _seg->speed;
#endif
uint16_t myCustomEffect0() {
handleAuto();
return (strip->getSpeed() / WS2812FXStripSettings.stripSize);
}
uint16_t myCustomEffect1() {
handleCustomWS();
return (strip->getSpeed() / WS2812FXStripSettings.stripSize);
}
#if defined(CUSTOM_WS2812FX_ANIMATIONS)
uint16_t myCustomEffect2() {
handleTV();
return (strip->getSpeed() / WS2812FXStripSettings.stripSize);
}
uint16_t myCustomEffect3() {
handleE131();
return (strip->getSpeed() / WS2812FXStripSettings.stripSize);
}
uint16_t myCustomEffect4() {
Fire2012();
return (strip->getSpeed() / WS2812FXStripSettings.stripSize);
}
uint16_t myCustomEffect5() {
Gradient();
return (strip->getSpeed() / WS2812FXStripSettings.stripSize);
} }
#endif #endif
File diff suppressed because it is too large Load Diff
+272 -155
View File
@@ -49,102 +49,7 @@
server.on("/upload", handleMinimalUpload); server.on("/upload", handleMinimalUpload);
server.on("/esp_status", HTTP_GET, []() { //get heap status, analog input value and all GPIO statuses in one json call server.on("/esp_status", HTTP_GET, []() { //get heap status, analog input value and all GPIO statuses in one json call
const size_t bufferSize = JSON_OBJECT_SIZE(31) + 1500; getESPStateJSON();
DynamicJsonDocument jsonBuffer(bufferSize);
JsonObject root = jsonBuffer.to<JsonObject>();
root["HOSTNAME"] = HOSTNAME;
root["version"] = SKETCH_VERSION;
root["heap"] = ESP.getFreeHeap();
root["sketch_size"] = ESP.getSketchSize();
root["free_sketch_space"] = ESP.getFreeSketchSpace();
root["flash_chip_size"] = ESP.getFlashChipSize();
root["flash_chip_real_size"] = ESP.getFlashChipRealSize();
root["flash_chip_speed"] = ESP.getFlashChipSpeed();
root["sdk_version"] = ESP.getSdkVersion();
root["core_version"] = ESP.getCoreVersion();
root["cpu_freq"] = ESP.getCpuFreqMHz();
root["chip_id"] = ESP.getFlashChipId();
#if defined(USE_WS2812FX_DMA)
#if USE_WS2812FX_DMA == 0
root["animation_lib"] = "WS2812FX_DMA";
#endif
#if USE_WS2812FX_DMA == 1
root["animation_lib"] = "WS2812FX_UART1";
#endif
#if USE_WS2812FX_DMA == 2
root["animation_lib"] = "WS2812FX_UART2";
#endif
#else
root["animation_lib"] = "WS2812FX";
#endif
root["ws2812_pin"] = WS2812FXStripSettings.pin;
root["led_count"] = WS2812FXStripSettings.stripSize;
root["rgb_order"] = WS2812FXStripSettings.RGBOrder;
if (strstr(WS2812FXStripSettings.RGBOrder, "W") != NULL) {
root["rgbw_mode"] = "ON";
} else {
root["rgbw_mode"] = "OFF";
}
#if defined(ENABLE_BUTTON)
root["button_mode"] = "ON";
root["button_pin"] = ENABLE_BUTTON;
#else
root["button_mode"] = "OFF";
#endif
#if defined(ENABLE_BUTTON_GY33)
root["button_gy33"] = "ON";
root["gy33_pin"] = ENABLE_BUTTON_GY33;
#else
root["button_gy33"] = "OFF";
#endif
#if defined(ENABLE_REMOTE)
root["ir_remote"] = "ON";
root["tsop_ir_pin"] = ENABLE_REMOTE;
#else
root["ir_remote"] = "OFF";
#endif
#if defined(ENABLE_MQTT)
#if ENABLE_MQTT == 0
root["mqtt"] = "MQTT";
#endif
#if ENABLE_MQTT == 1
root["mqtt"] = "AMQTT";
#endif
#else
root["mqtt"] = "OFF";
#endif
#if defined(ENABLE_HOMEASSISTANT)
root["home_assistant"] = "ON";
#else
root["home_assistant"] = "OFF";
#endif
#if defined(ENABLE_OTA)
#if ENABLE_OTA == 0
root["ota"] = "ARDUINO";
#endif
#if ENABLE_OTA == 1
root["ota"] = "HTTP";
#endif
#else
root["ota"] = "OFF";
#endif
#if defined(ENABLE_STATE_SAVE)
#if ENABLE_STATE_SAVE == 1
root["state_save"] = "SPIFFS";
#endif
#if ENABLE_STATE_SAVE == 0
root["state_save"] = "EEPROM";
#endif
#else
root["state_save"] = "OFF";
#endif
uint16_t msg_len = measureJson(root) + 1;
char * buffer = (char *) malloc(msg_len);
serializeJson(root, buffer, msg_len);
jsonBuffer.clear();
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "application/json", buffer);
free (buffer);
}); });
server.on("/restart", []() { server.on("/restart", []() {
@@ -179,26 +84,26 @@
server.on("/get_brightness", []() { server.on("/get_brightness", []() {
char str_brightness[4]; char str_brightness[4];
snprintf(str_brightness, sizeof(str_brightness), "%i", (int) (brightness / 2.55)); snprintf(str_brightness, sizeof(str_brightness), "%i", (int) (State.brightness / 2.55));
str_brightness[sizeof(str_brightness) - 1] = 0x00; str_brightness[sizeof(str_brightness) - 1] = 0x00;
server.sendHeader("Access-Control-Allow-Origin", "*"); server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", str_brightness ); server.send(200, "text/plain", str_brightness );
DBG_OUTPUT_PORT.printf("/get_brightness: %i\r\n", (int) (brightness / 2.55)); DBG_OUTPUT_PORT.printf("/get_brightness: %i\r\n", (int) (State.brightness / 2.55));
}); });
server.on("/get_speed", []() { server.on("/get_speed", []() {
char str_speed[4]; char str_speed[4];
snprintf(str_speed, sizeof(str_speed), "%i", ws2812fx_speed); snprintf(str_speed, sizeof(str_speed), "%i", segState.speed[State.segment]);
str_speed[sizeof(str_speed) - 1] = 0x00; str_speed[sizeof(str_speed) - 1] = 0x00;
server.sendHeader("Access-Control-Allow-Origin", "*"); server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", str_speed ); server.send(200, "text/plain", str_speed );
DBG_OUTPUT_PORT.printf("/get_speed: %i\r\n", ws2812fx_speed); DBG_OUTPUT_PORT.printf("/get_speed: %i\r\n", segState.speed[State.segment]);
}); });
server.on("/get_switch", []() { server.on("/get_switch", []() {
server.sendHeader("Access-Control-Allow-Origin", "*"); server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", (mode == OFF) ? "0" : "1" ); server.send(200, "text/plain", (State.mode == OFF) ? "0" : "1" );
DBG_OUTPUT_PORT.printf("/get_switch: %s\r\n", (mode == OFF) ? "0" : "1"); DBG_OUTPUT_PORT.printf("/get_switch: %s\r\n", (State.mode == OFF) ? "0" : "1");
}); });
server.on("/get_color", []() { server.on("/get_color", []() {
@@ -236,7 +141,7 @@
}); });
server.on("/status", []() { server.on("/status", []() {
getStatusJSON(); getStateJSON();
}); });
server.on("/config", []() { server.on("/config", []() {
@@ -253,107 +158,319 @@
} }
*/ */
// ToDo do not save if no change
bool updateStrip = false; bool _updateStrip = false;
bool updateConf = false; bool _updateConfig = false;
bool _updateState = false;
if(server.hasArg("ws_seg")){
uint8_t _ws_seg = server.arg("ws_seg").toInt();
_ws_seg = constrain(_ws_seg, 1, MAX_NUM_SEGMENTS - 1);
if (_ws_seg != Config.segments){
Config.segments = _ws_seg;
_updateStrip = true;
if (State.segment >= Config.segments) {
State.segment = Config.segments - 1;
_updateState = true;
}
}
}
if(server.hasArg("ws_cnt")){ if(server.hasArg("ws_cnt")){
uint16_t pixelCt = server.arg("ws_cnt").toInt(); uint16_t _stripSize = server.arg("ws_cnt").toInt();
if (pixelCt > 0) { if (_stripSize > 0) {
WS2812FXStripSettings.stripSize = constrain(pixelCt, 1, MAXLEDS); _stripSize = constrain(_stripSize, 1, MAXLEDS);
updateStrip = true; if (_stripSize != Config.stripSize) {
Config.stripSize = _stripSize;
_updateStrip = true;
}
} }
} }
if(server.hasArg("ws_rgbo")){ if(server.hasArg("ws_rgbo")){
char tmp_rgbOrder[5]; char _ws_rgbo[5];
snprintf(tmp_rgbOrder, sizeof(tmp_rgbOrder), "%s", server.arg("ws_rgbo").c_str()); snprintf(_ws_rgbo, sizeof(_ws_rgbo), "%s", server.arg("ws_rgbo").c_str());
tmp_rgbOrder[sizeof(tmp_rgbOrder) - 1] = 0x00; _ws_rgbo[sizeof(_ws_rgbo) - 1] = 0x00;
checkRGBOrder(tmp_rgbOrder); checkRGBOrder(_ws_rgbo);
updateStrip = true; _updateStrip = true;
} }
#if !defined(USE_WS2812FX_DMA) #if !defined(USE_WS2812FX_DMA)
if(server.hasArg("ws_pin")){ if(server.hasArg("ws_pin")){
if (checkPin(server.arg("ws_pin").toInt())) { if (checkPin(server.arg("ws_pin").toInt())) {
updateStrip = true; _updateStrip = true;
DBG_OUTPUT_PORT.print("Pin was set to: "); DBG_OUTPUT_PORT.print("Pin was set to: ");
DBG_OUTPUT_PORT.println(WS2812FXStripSettings.pin); DBG_OUTPUT_PORT.println(Config.pin);
} else { } else {
DBG_OUTPUT_PORT.println("invalid input!"); DBG_OUTPUT_PORT.println("invalid input or same value!");
} }
} }
#endif #endif
if(server.hasArg("ws_fxopt")){ if(_updateStrip) {
WS2812FXStripSettings.fxoptions = ((constrain(server.arg("ws_fxopt").toInt(), 0, 255)>>1)<<1); initStrip();
updateStrip = true;
}
if(updateStrip) {
mode = INIT_STRIP;
} }
if(server.hasArg("hostname")){ if(server.hasArg("hostname")){
snprintf(HOSTNAME, sizeof(HOSTNAME), "%s", server.arg("hostname").c_str()); char _hostname[sizeof(HOSTNAME)];
HOSTNAME[sizeof(HOSTNAME) - 1] = 0x00; snprintf(_hostname, sizeof(_hostname), "%s", server.arg("hostname").c_str());
updateConf = true; _hostname[sizeof(_hostname) - 1] = 0x00;
if (strcmp(HOSTNAME, _hostname) != 0) {
strcpy(HOSTNAME, _hostname);
_updateConfig = true;
}
} }
#if defined(ENABLE_MQTT) #if defined(ENABLE_MQTT)
if(server.hasArg("mqtt_host")){ if(server.hasArg("mqtt_host")){
snprintf(mqtt_host, sizeof(mqtt_host), "%s", server.arg("mqtt_host").c_str()); char _mqtt_host[sizeof(mqtt_host)];
mqtt_host[sizeof(mqtt_host) - 1] = 0x00; snprintf(_mqtt_host, sizeof(_mqtt_host), "%s", server.arg("mqtt_host").c_str());
updateConf = true; _mqtt_host[sizeof(_mqtt_host) - 1] = 0x00;
if (strcmp(mqtt_host, _mqtt_host) != 0) {
strcpy(mqtt_host, _mqtt_host);
_updateConfig = true;
}
} }
if(server.hasArg("mqtt_port")){ if(server.hasArg("mqtt_port")){
if ((server.arg("mqtt_port").toInt() >= 0) && (server.arg("mqtt_port").toInt() <=65535)) { uint16_t _mqtt_port = constrain(server.arg("mqtt_port").toInt(), 1, 65535);
mqtt_port = server.arg("mqttport").toInt(); if (_mqtt_port != mqtt_port) {
updateConf = true; mqtt_port = _mqtt_port;
_updateConfig = true;
} }
} }
if(server.hasArg("mqtt_user")){ if(server.hasArg("mqtt_user")){
snprintf(mqtt_user, sizeof(mqtt_user), "%s", server.arg("mqtt_user").c_str()); char _mqtt_user[sizeof(mqtt_user)];
mqtt_user[sizeof(mqtt_user) - 1] = 0x00; snprintf(_mqtt_user, sizeof(_mqtt_user), "%s", server.arg("mqtt_user").c_str());
updateConf = true; _mqtt_user[sizeof(mqtt_user) - 1] = 0x00;
if (strcmp(mqtt_user, _mqtt_user) != 0) {
strcpy(mqtt_user, _mqtt_user);
_updateConfig = true;
}
} }
if(server.hasArg("mqtt_pass")){ if(server.hasArg("mqtt_pass")){
snprintf(mqtt_pass, sizeof(mqtt_pass), "%s", server.arg("mqtt_pass").c_str()); char _mqtt_pass[sizeof(mqtt_pass)];
mqtt_pass[sizeof(mqtt_pass) - 1] = 0x00; snprintf(_mqtt_pass, sizeof(_mqtt_pass), "%s", server.arg("mqtt_pass").c_str());
updateConf = true; _mqtt_pass[sizeof(_mqtt_pass) - 1] = 0x00;
if (strcmp(mqtt_pass, _mqtt_pass) != 0) {
strcpy(mqtt_pass, _mqtt_pass);
_updateConfig = true;
} }
if (updateConf) { }
if (_updateConfig) {
initMqtt(); initMqtt();
} }
#endif #endif
if(server.hasArg("trans_effect")){ if(server.hasArg("trans_effect")){
transEffect = server.arg("trans_effect").toInt(); Config.transEffect = server.arg("trans_effect").toInt();
updateConf = true; _updateConfig = true;
} }
#if defined(ENABLE_STATE_SAVE) #if defined(ENABLE_STATE_SAVE)
if (updateStrip || updateConf) { if (_updateStrip || _updateConfig) {
if(!settings_save_conf.active()) settings_save_conf.once(3, tickerSaveConfig); DBG_OUTPUT_PORT.println("Saving config.json!");
if(!save_conf.active()) save_conf.once(3, tickerSaveConfig);
}
if (_updateState) {
DBG_OUTPUT_PORT.println("Saving stripstate.json!");
if(!save_state.active()) save_state.once(3, tickerSaveState);
} }
#endif #endif
updateStrip = false; _updateStrip = false;
updateConf = false; _updateConfig = false;
_updateState = false;
getConfigJSON(); getConfigJSON();
}); });
server.on("/off", []() { server.on("/off", []() {
mode = OFF; if (State.mode == OFF) { State.mode = SET; } else { State.mode = OFF; };
getStatusJSON(); getStateJSON();
#if defined(ENABLE_STATE_SAVE)
DBG_OUTPUT_PORT.println("Saving stripstate.json!");
if(!save_state.active()) save_state.once(3, tickerSaveState);
#endif
}); });
server.on("/on", []() { server.on("/on", []() {
mode = SET; if (prevmode == OFF) {
getStatusJSON(); State.mode = SET;
getStateJSON();
#if defined(ENABLE_STATE_SAVE)
DBG_OUTPUT_PORT.println("Saving stripstate.json!");
if(!save_state.active()) save_state.once(3, tickerSaveState);
#endif
} else {
getStateJSON();
}
}); });
server.on("/set", []() { server.on("/set", []() {
prevmode = HOLD; prevmode = HOLD;
ws2812fx_mode = FX_MODE_STATIC; boolean _updateState = false;
mode = SET; boolean _updateSegState = false;
getArgs(); // Segment
getStatusJSON(); if ((server.arg("seg") != "") && (server.arg("seg").toInt() >= 0) && (server.arg("seg").toInt() < Config.segments)) {
uint8_t _seg = server.arg("seg").toInt();
if (prevsegment != _seg) {
prevsegment = State.segment;
State.segment = _seg;
getSegmentParams(State.segment);
//memcpy(hexcolors_trans, segState.colors[State.segment], sizeof(hexcolors_trans));
State.mode = SET;
_updateState = true;
}
}
if ((server.arg("start") != "") && (server.arg("start").toInt() >= 0) && (server.arg("start").toInt() <= segState.stop)) {
uint16_t _seg_start = server.arg("start").toInt();
_seg_start = constrain(segState.start, 0, Config.stripSize -1);
if (_seg_start != segState.start) {
segState.start = _seg_start;
setSegmentSize();
_updateSegState = true;
}
}
if ((server.arg("stop") != "") && (server.arg("stop").toInt() >= segState.start) && (server.arg("stop").toInt() <= Config.stripSize)) {
uint16_t _seg_stop = server.arg("stop").toInt();
_seg_stop = constrain(_seg_stop, segState.start, Config.stripSize - 1);
if (_seg_stop != segState.stop) {
segState.stop = _seg_stop;
setSegmentSize();
_updateSegState = true;
}
}
if(server.hasArg("fxopt")){
uint8_t _fx_options = ((constrain(server.arg("fxopt").toInt(), 0, 255)>>1)<<1);
if (_fx_options != segState.options) {
segState.options = _fx_options;
strip->setOptions(State.segment, segState.options);
_updateSegState = true;
}
}
//color wrgb
if (server.arg("rgb") != "") {
uint32_t rgb = (uint32_t) strtoul(server.arg("rgb").c_str(), NULL, 16);
main_color.white = ((rgb >> 24) & 0xFF);
main_color.red = ((rgb >> 16) & 0xFF);
main_color.green = ((rgb >> 8) & 0xFF);
main_color.blue = ((rgb >> 0) & 0xFF);
_updateSegState = true;
} else {
if ((server.arg("r") != "") && (server.arg("r").toInt() >= 0) && (server.arg("r").toInt() <= 255)) {
main_color.red = server.arg("r").toInt();
_updateSegState = true;
}
if ((server.arg("g") != "") && (server.arg("g").toInt() >= 0) && (server.arg("g").toInt() <= 255)) {
main_color.green = server.arg("g").toInt();
_updateSegState = true;
}
if ((server.arg("b") != "") && (server.arg("b").toInt() >= 0) && (server.arg("b").toInt() <= 255)) {
main_color.blue = server.arg("b").toInt();
_updateSegState = true;
}
if ((server.arg("w") != "") && (server.arg("w").toInt() >= 0) && (server.arg("w").toInt() <= 255)){
main_color.white = server.arg("w").toInt();
_updateSegState = true;
}
}
if (server.arg("rgb2") != "") {
uint32_t rgb2 = (uint32_t) strtoul(server.arg("rgb2").c_str(), NULL, 16);
back_color.white = ((rgb2 >> 24) & 0xFF);
back_color.red = ((rgb2 >> 16) & 0xFF);
back_color.green = ((rgb2 >> 8) & 0xFF);
back_color.blue = ((rgb2 >> 0) & 0xFF);
_updateSegState = true;
} else {
if ((server.arg("r2") != "") && (server.arg("r2").toInt() >= 0) && (server.arg("r2").toInt() <= 255)) {
back_color.red = server.arg("r2").toInt();
_updateSegState = true;
}
if ((server.arg("g2") != "") && (server.arg("g2").toInt() >= 0) && (server.arg("g2").toInt() <= 255)) {
back_color.green = server.arg("g2").toInt();
_updateSegState = true;
}
if ((server.arg("b2") != "") && (server.arg("b2").toInt() >= 0) && (server.arg("b2").toInt() <= 255)) {
back_color.blue = server.arg("b2").toInt();
_updateSegState = true;
}
if ((server.arg("w2") != "") && (server.arg("w2").toInt() >= 0) && (server.arg("w2").toInt() <= 255)){
back_color.white = server.arg("w2").toInt();
_updateSegState = true;
}
}
if (server.arg("rgb3") != "") {
uint32_t rgb3 = (uint32_t) strtoul(server.arg("rgb3").c_str(), NULL, 16);
xtra_color.white = ((rgb3 >> 24) & 0xFF);
xtra_color.red = ((rgb3 >> 16) & 0xFF);
xtra_color.green = ((rgb3 >> 8) & 0xFF);
xtra_color.blue = ((rgb3 >> 0) & 0xFF);
_updateSegState = true;
} else {
if ((server.arg("r3") != "") && (server.arg("r3").toInt() >= 0) && (server.arg("r3").toInt() <= 255)) {
xtra_color.red = server.arg("r3").toInt();
_updateSegState = true;
}
if ((server.arg("g3") != "") && (server.arg("g3").toInt() >= 0) && (server.arg("g3").toInt() <= 255)) {
xtra_color.green = server.arg("g3").toInt();
_updateSegState = true;
}
if ((server.arg("b3") != "") && (server.arg("b3").toInt() >= 0) && (server.arg("b3").toInt() <= 255)) {
xtra_color.blue = server.arg("b3").toInt();
_updateSegState = true;
}
if ((server.arg("w3") != "") && (server.arg("w3").toInt() >= 0) && (server.arg("w3").toInt() <= 255)){
xtra_color.white = server.arg("w3").toInt();
_updateSegState = true;
}
}
main_color.red = constrain(main_color.red, 0, 255);
main_color.green = constrain(main_color.green, 0, 255);
main_color.blue = constrain(main_color.blue, 0, 255);
main_color.white = constrain(main_color.white, 0, 255);
back_color.red = constrain(back_color.red, 0, 255);
back_color.green = constrain(back_color.green, 0, 255);
back_color.blue = constrain(back_color.blue, 0, 255);
back_color.white = constrain(back_color.white, 0, 255);
xtra_color.red = constrain(xtra_color.red, 0, 255);
xtra_color.green = constrain(xtra_color.green, 0, 255);
xtra_color.blue = constrain(xtra_color.blue, 0, 255);
xtra_color.white = constrain(xtra_color.white, 0, 255);
// Speed
if ((server.arg("s") != "") && (server.arg("s").toInt() >= 0) && (server.arg("s").toInt() <= 255)) {
segState.speed[State.segment] = constrain(server.arg("s").toInt(), 0, 255);
_updateSegState = true;
}
//Mode
if ((server.arg("m") != "") && (server.arg("m").toInt() >= 0) && (server.arg("m").toInt() <= strip->getModeCount())) {
fx_mode = constrain(server.arg("m").toInt(), 0, strip->getModeCount() - 1);
if (fx_mode != segState.mode[State.segment]) {
_updateSegState = true;
}
}
// Brightness
if ((server.arg("c") != "") && (server.arg("c").toInt() >= 0) && (server.arg("c").toInt() <= 100)) {
State.brightness = constrain((int) server.arg("c").toInt() * 2.55, 0, 255);
} else if ((server.arg("p") != "") && (server.arg("p").toInt() >= 0) && (server.arg("p").toInt() <= 255)) {
State.brightness = constrain(server.arg("p").toInt(), 0, 255);
}
if (strip->getBrightness() != State.brightness) {
State.mode = SET;
_updateState = true;
}
DBG_OUTPUT_PORT.printf("Get Args: %s\r\n", listStateJSONfull());
getStateJSON();
#if defined(ENABLE_STATE_SAVE)
if (_updateState) {
DBG_OUTPUT_PORT.println("Saving stripstate.json!");
if(!save_state.active()) save_state.once(3, tickerSaveState);
}
if (_updateSegState) {
DBG_OUTPUT_PORT.println("Saving stripstate_segment.json!");
State.mode = SET;
if(!save_seg_state.active()) save_seg_state.once(3, tickerSaveSegmentState);
}
#endif
_updateState = false;
_updateSegState = false;
}); });
+1 -1
View File
@@ -1 +1 @@
#define SKETCH_VERSION "3.0.0.BETA1" #define SKETCH_VERSION "3.1.0.BETA3"
+34
View File
@@ -188,4 +188,38 @@
* Version Bump to 3.0.0.BETA1 * Version Bump to 3.0.0.BETA1
* further code changes * further code changes
* bugfixes * bugfixes
*
* 30 September 2019
* Version Bump to 3.1.0.ALPHA1
* further code changes
* removal of saving to EEPROM
* first integration of multi segments
*
* 3 October 2019
* Version Bump to 3.1.0.ALPHA2
* further code changes
* further integration of multi segments
* integration of multi segments to GUI
*
* 5 October 2019
* Version Bump to 3.1.0.ALPHA2
* further code changes
* further integration of multi segments
* known problem: as always: AUTOPLAY (as it is not multi segment capable yet)
*
* 07 October
* Version Bump to 3.1.0.BETA1
* bugfixes
* adressed issue: #39 uncooment //#define ENABLE_MQTT_INCLUDE_IP in defninitions.h
*
* 09 October
* Version Bump to 3.1.0.BETA2
* bugfixes
* implemented https://github.com/FabLab-Luenen/McLighting/commit/589806d0fda737011426754a6d84c88535ded688
*
* 20 October
* Version Bump to 3.1.0.BETA3
* Bugfixes
* adresse issue: #39
*
*/ */
+3 -1
View File
@@ -182,7 +182,9 @@
var mkfile = document.createElement("button"); var mkfile = document.createElement("button");
mkfile.innerHTML = 'MkFile'; mkfile.innerHTML = 'MkFile';
document.getElementById(element).appendChild(mkfile); document.getElementById(element).appendChild(mkfile);
var para = document.createElement("text");
para.innerHTML = " Press Ctrl-S for save, Ctrl-Z for undo, Ctrl-Shift-Z for redo";
document.getElementById(element).appendChild(para);
function httpPostProcessRequest(){ function httpPostProcessRequest(){
if (xmlHttp.readyState == 4){ if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText); if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
Binary file not shown.
+286 -161
View File
@@ -877,7 +877,7 @@ input[type=number], label{
</div> </div>
</div> </div>
</div> </div>
<div class="flex xs12 sm7"> <div class="flex xs12 sm8">
<div class="sliders container"> <div class="sliders container">
<div class="color-wrap" style="display:none"> <div class="color-wrap" style="display:none">
<div id="color-display"></div> <div id="color-display"></div>
@@ -912,6 +912,13 @@ input[type=number], label{
<input type="number" id="speedNum"> <input type="number" id="speedNum">
<input value="255" type="range" min="0" max="255" id="speed"> <input value="255" type="range" min="0" max="255" id="speed">
</div> </div>
<div id="segments" class="container" style="text-align: left;">
<div class="layout row wrap">
<div class="flex xs12 sm2" id="selectSegLbl" style="text-align: left;"><p>selectSeg</p>
<select id="selectseg" class="custom-select" style="border: 2px solid #aaaaaa; border-radius: 6px; width:90%; "></select>
</div>
</div>
</div>
<div id="message" class="container hidden" style="text-align: left;"> <div id="message" class="container hidden" style="text-align: left;">
<div id="wsmessageLbl" style="text-align: left;"><p>wsMessage</p> <div id="wsmessageLbl" style="text-align: left;"><p>wsMessage</p>
<input type="text" id="wsmessage" style="border: 2px solid #aaaaaa; border-radius: 6px; width:100%;" /> <input type="text" id="wsmessage" style="border: 2px solid #aaaaaa; border-radius: 6px; width:100%;" />
@@ -959,14 +966,25 @@ input[type=number], label{
</div> </div>
</div> </div>
<div class="layout row wrap"> <div class="layout row wrap">
<div class="flex xs12 sm4"><p>selectCount</p> <div class="flex xs12 sm3"><p>selectSegCnt</p>
<input type="number" min="0" max="65535" id="selectcount" style="border: 2px solid #aaaaaa; border-radius: 6px; width:100%;" /> <input type="number" min="1" max="9" id="selectsegcnt" style="border: 2px solid #aaaaaa; border-radius: 6px; width:50%;" />
</div> </div>
<div class="flex xs12 sm4"><p>selectRGBO</p> <div class="flex xs12 sm3"><p>selectCount</p>
<input type="number" min="0" max="65535" id="selectcount" style="border: 2px solid #aaaaaa; border-radius: 6px; width:50%;" />
</div>
<div class="flex xs12 sm3"><p>selectRGBO</p>
<select id="selectrgbo" class="custom-select"></select> <select id="selectrgbo" class="custom-select"></select>
</div> </div>
<div class="flex xs12 sm4"><p>selectPin</p> <div class="flex xs12 sm3"><p>selectPin</p>
<input type="number" min="0" max="16" id="selectpin" style="border: 2px solid #aaaaaa; border-radius: 6px; width:100%;" /> <input type="number" min="0" max="16" id="selectpin" style="border: 2px solid #aaaaaa; border-radius: 6px; width:50%;" />
</div>
</div>
<div class="layout row wrap">
<div class="flex xs12 sm6"><p>segStart</p>
<input type="number" min="0" max="*jsvariable" id="segstart" style="border: 2px solid #aaaaaa; border-radius: 6px; width:90%;" />
</div>
<div class="flex xs12 sm6"><p>segStop</p>
<input type="number" min="0" max="*jsvariable" id="segstop" style="border: 2px solid #aaaaaa; border-radius: 6px; width:90%;" />
</div> </div>
</div> </div>
<div class="layout row wrap"> <div class="layout row wrap">
@@ -1030,6 +1048,7 @@ var language = {
connectError2: " times. Please use the RECONNECT button to try again.", connectError2: " times. Please use the RECONNECT button to try again.",
loadModes: "Loading modes ...", // This language-string is not translated (settings not loaded yet) loadModes: "Loading modes ...", // This language-string is not translated (settings not loaded yet)
loadSettings: "Loading settings ...", // This language-string is not translated (settings not loaded yet) loadSettings: "Loading settings ...", // This language-string is not translated (settings not loaded yet)
loadConfig: "Loading configuration ...",
loadWebsock: "Connecting websockets ...", loadWebsock: "Connecting websockets ...",
loadReady: "Ready ...", loadReady: "Ready ...",
loadError: "Error loading animation modes, please try again...", // This language-string is not translated (settings not loaded yet) loadError: "Error loading animation modes, please try again...", // This language-string is not translated (settings not loaded yet)
@@ -1043,6 +1062,9 @@ var language = {
white: "White", white: "White",
not_greater: "cannot enter numbers greater than 255", not_greater: "cannot enter numbers greater than 255",
not_less: "cannot enter numbers less than 0", not_less: "cannot enter numbers less than 0",
selectSeg: "Select segment",
segStart: "First LED of selected segment",
segStop: "Last LED of selected segment",
wsMessage: "Websocket Message:", wsMessage: "Websocket Message:",
selectLanguage: "Select Language:", selectLanguage: "Select Language:",
selectHostname: "Hostname:", selectHostname: "Hostname:",
@@ -1050,6 +1072,7 @@ var language = {
selectMQTTPort: "and Port:", selectMQTTPort: "and Port:",
selectMQTTUser: "MQTT Username:", selectMQTTUser: "MQTT Username:",
selectMQTTPass: "MQTT Password:", selectMQTTPass: "MQTT Password:",
selectSegCnt: "Number of Segments:",
selectCount: "Strip LED Count:", selectCount: "Strip LED Count:",
selectRGBO: "RGB Order:", selectRGBO: "RGB Order:",
selectPin: "Strip GPIO Pin:", selectPin: "Strip GPIO Pin:",
@@ -1086,6 +1109,7 @@ var language = {
connectError2: " keer geprobeerd. Gebruik de Verbind opnieuw knop om opnieuw te proberen.", connectError2: " keer geprobeerd. Gebruik de Verbind opnieuw knop om opnieuw te proberen.",
loadModes: "Modes laden...", // This language-string is not translated (settings not loaded yet) loadModes: "Modes laden...", // This language-string is not translated (settings not loaded yet)
loadSettings: "Instellingen laden...", // This language-string is not translated (settings not loaded yet) loadSettings: "Instellingen laden...", // This language-string is not translated (settings not loaded yet)
loadConfig: "Configuratie laden ...",
loadWebsock: "Websockets verbinden...", loadWebsock: "Websockets verbinden...",
loadReady: "Klaar...", loadReady: "Klaar...",
loadError: "Fout bij laden van animatie modes, probeer opnieuw...", // This language-string is not translated (settings not loaded yet) loadError: "Fout bij laden van animatie modes, probeer opnieuw...", // This language-string is not translated (settings not loaded yet)
@@ -1099,6 +1123,9 @@ var language = {
white: "Wit", white: "Wit",
not_greater: "Geen nummers hoger dan 255", not_greater: "Geen nummers hoger dan 255",
not_less: "Geen nummers lager dan 0", not_less: "Geen nummers lager dan 0",
selectSeg: "Selecteer segment",
segStart: "Eerste LED van huidige segmenten",
segStop: "Laatste LED van huidige segmenten",
wsMessage: "Websocket message:", wsMessage: "Websocket message:",
selectLanguage: "Selecteer Taal:", selectLanguage: "Selecteer Taal:",
selectHostname: "Hostname:", selectHostname: "Hostname:",
@@ -1106,6 +1133,7 @@ var language = {
selectMQTTPort: "en Port:", selectMQTTPort: "en Port:",
selectMQTTUser: "MQTT gebruikersnaam:", selectMQTTUser: "MQTT gebruikersnaam:",
selectMQTTPass: "MQTT wachtwoord:", selectMQTTPass: "MQTT wachtwoord:",
selectSegCnt: "Number of Segments:",
selectCount: "LED nummer:", selectCount: "LED nummer:",
selectPin: "Strip GPIO Pin:", selectPin: "Strip GPIO Pin:",
selectRGBO: "RGB Order:", selectRGBO: "RGB Order:",
@@ -1142,6 +1170,7 @@ var language = {
connectError2: " mal versucht. Benutze WIEDER VERBINDEN, um es nochmal zu probieren.", connectError2: " mal versucht. Benutze WIEDER VERBINDEN, um es nochmal zu probieren.",
loadModes: "Lade Modi ...", // This language-string is not translated (settings not loaded yet) loadModes: "Lade Modi ...", // This language-string is not translated (settings not loaded yet)
loadSettings: "Lade Einstellungen ...", // This language-string is not translated (settings not loaded yet) loadSettings: "Lade Einstellungen ...", // This language-string is not translated (settings not loaded yet)
loadConfig: "Lade Konfiguration ...",
loadWebsock: "Verbinde Websockets ...", loadWebsock: "Verbinde Websockets ...",
loadReady: "Fertig ...", loadReady: "Fertig ...",
loadError: "Fehler beim Laden der Animations-Modi, bitte nochmal versuchen...", // This language-string is not translated (settings not loaded yet) loadError: "Fehler beim Laden der Animations-Modi, bitte nochmal versuchen...", // This language-string is not translated (settings not loaded yet)
@@ -1155,6 +1184,9 @@ var language = {
white: "Weiß", white: "Weiß",
not_greater: "Akzeptiere keine Nummern größer 255", not_greater: "Akzeptiere keine Nummern größer 255",
not_less: "Akzeptiere keine Nummern kleiner 0", not_less: "Akzeptiere keine Nummern kleiner 0",
selectSeg: "Segment wählen",
segStart: "Erste LED des gewählten Segments",
segStop: "Letzte LED des gewählten Segments",
wsMessage: "Websocket Message:", wsMessage: "Websocket Message:",
selectLanguage: "Sprache auswählen:", selectLanguage: "Sprache auswählen:",
selectHostname: "Hostname:", selectHostname: "Hostname:",
@@ -1162,6 +1194,7 @@ var language = {
selectMQTTPort: "und Port:", selectMQTTPort: "und Port:",
selectMQTTUser: "MQTT Username:", selectMQTTUser: "MQTT Username:",
selectMQTTPass: "MQTT Password:", selectMQTTPass: "MQTT Password:",
selectSegCnt: "Anzahl Segmente:",
selectCount: "Strip LED Anzahl:", selectCount: "Strip LED Anzahl:",
selectRGBO: "RGB Reihenfolge:", selectRGBO: "RGB Reihenfolge:",
selectPin: "Strip GPIO Pin:", selectPin: "Strip GPIO Pin:",
@@ -1281,19 +1314,31 @@ var config = {
mqtt_port: 0, mqtt_port: 0,
mqtt_user: "", mqtt_user: "",
mqtt_pass: "", mqtt_pass: "",
ws_seg: 1,
ws_cnt: 0, ws_cnt: 0,
ws_rgbo: "", ws_rgbo: "",
ws_pin: 0, ws_pin: 0,
ws_fxopt: 0, ws_trans: false,
enable_rgbw: false, enable_rgbw: false
transitionEffects: true
}; };
var data = { var state = {
mode: 0, mode: 0,
segment: 0,
brightness: 0
}
var segstate = {
start: 0,
stop: 0,
mode: null,
speed: 0,
color: {w:0, r:0, g:0, b:0, hex:"00000000", w2:0, r2:0, g2:0, b2:0, hex2:"00000000", w3:0, r3:0, g3:0, b3:0, hex3:"00000000"}, color: {w:0, r:0, g:0, b:0, hex:"00000000", w2:0, r2:0, g2:0, b2:0, hex2:"00000000", w3:0, r3:0, g3:0, b3:0, hex3:"00000000"},
brightness: 192, ws_fxopt: 0
speed: 192, }
ws2812fx_mode: null,
var data = {
init: true,
color_num: 1, color_num: 1,
modes: [], modes: [],
connection: null, connection: null,
@@ -1301,7 +1346,6 @@ var data = {
num_additional_connections: 0, num_additional_connections: 0,
is_connected: false, is_connected: false,
refresh_interval: 0, refresh_interval: 0,
init: true,
color_disabled: false color_disabled: false
}; };
var sendIt; // Timer to prevent lots of sending var sendIt; // Timer to prevent lots of sending
@@ -1331,17 +1375,17 @@ function displayColors(all = false) {
clearTimeout(sendIt); clearTimeout(sendIt);
sendIt = setTimeout(function() { set_color(); }, 50); sendIt = setTimeout(function() { set_color(); }, 50);
} else { } else {
document.getElementById("colorSel1").style.backgroundColor = `rgb(${data.color.r}, ${data.color.g}, ${data.color.b})`; document.getElementById("colorSel1").style.backgroundColor = `rgb(${segstate.color.r}, ${segstate.color.g}, ${segstate.color.b})`;
document.getElementById("colorHex1").innerHTML = "#" + data.color.hex; document.getElementById("colorHex1").innerHTML = "#" + segstate.color.hex;
document.getElementById("colorSel2").style.backgroundColor = `rgb(${data.color.r2}, ${data.color.g2}, ${data.color.b2})`; document.getElementById("colorSel2").style.backgroundColor = `rgb(${segstate.color.r2}, ${segstate.color.g2}, ${segstate.color.b2})`;
document.getElementById("colorHex2").innerHTML = "#" + data.color.hex2; document.getElementById("colorHex2").innerHTML = "#" + segstate.color.hex2;
document.getElementById("colorSel3").style.backgroundColor = `rgb(${data.color.r3}, ${data.color.g3}, ${data.color.b3})`; document.getElementById("colorSel3").style.backgroundColor = `rgb(${segstate.color.r3}, ${segstate.color.g3}, ${segstate.color.b3})`;
document.getElementById("colorHex3").innerHTML = "#" + data.color.hex3; document.getElementById("colorHex3").innerHTML = "#" + segstate.color.hex3;
} }
} }
// initial color val numbers when DOM is loaded // initial color val numbers when DOM is loaded
function colorNumrVals(){ function colorNumVals(){
redNumVal.value = red.value; redNumVal.value = red.value;
greenNumVal.value = green.value; greenNumVal.value = green.value;
blueNumVal.value = blue.value; blueNumVal.value = blue.value;
@@ -1377,44 +1421,44 @@ function initSliderColors(){
function changeRangeNumVal(){ function changeRangeNumVal(){
redNumVal.addEventListener('change', ()=>{ redNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255 // make sure numbers are entered between 0 to 255
red.value = checkNumVal(redNumVal, red.value); red.value = checkNumVal8(redNumVal, red.value);
if (data.color_num === 1) data.color.r = red.value; if (data.color_num === 1) segstate.color.r = red.value;
if (data.color_num === 2) data.color.r2 = red.value; if (data.color_num === 2) segstate.color.r2 = red.value;
if (data.color_num === 3) data.color.r3 = red.value; if (data.color_num === 3) segstate.color.r3 = red.value;
initSliderColors(); initSliderColors();
displayColors(); displayColors();
}); });
greenNumVal.addEventListener('change', ()=>{ greenNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255 // make sure numbers are entered between 0 to 255
green.value = checkNumVal(greenNumVal, green.value); green.value = checkNumVal8(greenNumVal, green.value);
if (data.color_num === 1) data.color.g = green.value; if (data.color_num === 1) segstate.color.g = green.value;
if (data.color_num === 2) data.color.g2 = green.value; if (data.color_num === 2) segstate.color.g2 = green.value;
if (data.color_num === 3) data.color.g3 = green.value; if (data.color_num === 3) segstate.color.g3 = green.value;
initSliderColors(); initSliderColors();
displayColors(); displayColors();
}); });
blueNumVal.addEventListener('change', ()=>{ blueNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255 // make sure numbers are entered between 0 to 255
blue.value = checkNumVal(blueNumVal, blue.value); blue.value = checkNumVal8(blueNumVal, blue.value);
if (data.color_num === 1) data.color.b = blue.value; if (data.color_num === 1) segstate.color.b = blue.value;
if (data.color_num === 2) data.color.b2 = blue.value; if (data.color_num === 2) segstate.color.b2 = blue.value;
if (data.color_num === 3) data.color.b3 = blue.value; if (data.color_num === 3) segstate.color.b3 = blue.value;
initSliderColors(); initSliderColors();
displayColors(); displayColors();
}); });
whiteNumVal.addEventListener('change', ()=>{ whiteNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255 // make sure numbers are entered between 0 to 255
white.value = checkNumVal(whiteNumVal, white.value); white.value = checkNumVal8(whiteNumVal, white.value);
if (data.color_num === 1) data.color.w = white.value; if (data.color_num === 1) segstate.color.w = white.value;
if (data.color_num === 2) data.color.w2 = white.value; if (data.color_num === 2) segstate.color.w2 = white.value;
if (data.color_num === 3) data.color.w3 = white.value; if (data.color_num === 3) segstate.color.w3 = white.value;
initSliderColors(); initSliderColors();
displayColors(); displayColors();
}); });
brightNumVal.addEventListener('change', ()=>{ brightNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255 // make sure numbers are entered between 0 to 255
bright.value = checkNumVal(brightNumVal, bright.value); bright.value = checkNumVal8(brightNumVal, bright.value);
data.brightness = bright.value; state.brightness = bright.value;
initSliderColors(); initSliderColors();
// Send Brightness // Send Brightness
clearTimeout(sendIt); clearTimeout(sendIt);
@@ -1422,14 +1466,14 @@ function changeRangeNumVal(){
}); });
speedNumVal.addEventListener('change', ()=>{ speedNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255 // make sure numbers are entered between 0 to 255
speed.value = checkNumVal(speedNumVal, speed.value); speed.value = checkNumVal8(speedNumVal, speed.value);
data.speed = speed.value; segstate.speed = speed.value;
// Send Speed // Send Speed
clearTimeout(sendIt); clearTimeout(sendIt);
sendIt = setTimeout(function() { set_speed(); }, 50); sendIt = setTimeout(function() { set_speed(); }, 50);
}); });
} }
function checkNumVal(numVal, curVal) { function checkNumVal8(numVal, curVal) {
if(numVal.value > 255) { if(numVal.value > 255) {
alert(language[settings.lang]["not_greater"]); alert(language[settings.lang]["not_greater"]);
numVal.value = curVal; numVal.value = curVal;
@@ -1440,6 +1484,17 @@ function checkNumVal(numVal, curVal) {
return numVal.value; return numVal.value;
} }
function checkNumVal16(numVal, curVal) {
if(numVal.value > 65535) {
alert(language[settings.lang]["not_greater"]);
numVal.value = curVal;
} else if(numVal.value < 0) {
alert(language[settings.lang]["not_less"]);
numVal.value = curVal;
}
return numVal.value;
}
// Color Sliders controls // Color Sliders controls
function initcolorSliders(){ function initcolorSliders(){
var event = new Event('change'); var event = new Event('change');
@@ -1447,7 +1502,7 @@ function initcolorSliders(){
displayColors(); displayColors();
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
// Trigger onChange event to send value // Trigger onChange event to send value
redNumVal.dispatchEvent(event); redNumVal.dispatchEvent(event);
}); });
@@ -1456,7 +1511,7 @@ function initcolorSliders(){
displayColors(); displayColors();
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
// Trigger onChange event to send value // Trigger onChange event to send value
greenNumVal.dispatchEvent(event); greenNumVal.dispatchEvent(event);
}); });
@@ -1465,7 +1520,7 @@ function initcolorSliders(){
displayColors(); displayColors();
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
// Trigger onChange event to send value // Trigger onChange event to send value
blueNumVal.dispatchEvent(event); blueNumVal.dispatchEvent(event);
}); });
@@ -1474,7 +1529,7 @@ function initcolorSliders(){
displayColors(); displayColors();
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
// Trigger onChange event to send value // Trigger onChange event to send value
whiteNumVal.dispatchEvent(event); whiteNumVal.dispatchEvent(event);
}); });
@@ -1482,14 +1537,14 @@ function initcolorSliders(){
bright.addEventListener('input', () => { bright.addEventListener('input', () => {
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
// Trigger onChange event to send value // Trigger onChange event to send value
brightNumVal.dispatchEvent(event); brightNumVal.dispatchEvent(event);
}); });
speed.addEventListener('input', () => { speed.addEventListener('input', () => {
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
// Trigger onChange event to send value // Trigger onChange event to send value
speedNumVal.dispatchEvent(event); speedNumVal.dispatchEvent(event);
}); });
@@ -1518,8 +1573,11 @@ function xhttp(url, post, callback) {
xhr.send(post); xhr.send(post);
} }
function getModes() { function getModes() {
document.getElementById("percentage").innerHTML = "0%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "0,100");
document.getElementById("modal-content").innerHTML = language.en.loadModes;
xhttp("http://" + host + "/get_modes", false, function(e) { xhttp("http://" + host + "/get_modes", false, function(e) {
//console.log("Getting modes list via REST:", e); console.log("Getting modes list via REST:", e);
if (e && e.substring(0,6) !== "ERROR!") { if (e && e.substring(0,6) !== "ERROR!") {
modes = JSON.parse(e); modes = JSON.parse(e);
if (typeof modes[0] !== "undefined") { if (typeof modes[0] !== "undefined") {
@@ -1538,6 +1596,9 @@ function getModes() {
} }
function getConfig() { function getConfig() {
document.getElementById("percentage").innerHTML = "75%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "75,100");
document.getElementById("modal-content").innerHTML = language.en.loadConfig;
xhttp("http://" + host + "/config", false, function(e) { xhttp("http://" + host + "/config", false, function(e) {
console.log("Getting config via REST:", e); console.log("Getting config via REST:", e);
if (e && e.substring(0,6) !== "ERROR!") { if (e && e.substring(0,6) !== "ERROR!") {
@@ -1548,14 +1609,14 @@ function getConfig() {
if (typeof res.mqtt_port !== "undefined") config.mqtt_port = res.mqtt_port; if (typeof res.mqtt_port !== "undefined") config.mqtt_port = res.mqtt_port;
if (typeof res.mqtt_user !== "undefined") config.mqtt_user = res.mqtt_user; if (typeof res.mqtt_user !== "undefined") config.mqtt_user = res.mqtt_user;
if (typeof res.mqtt_pass !== "undefined") config.mqtt_pass = res.mqtt_pass; if (typeof res.mqtt_pass !== "undefined") config.mqtt_pass = res.mqtt_pass;
if (typeof res.ws_seg !== "undefined") config.ws_seg = res.ws_seg;
if (typeof res.ws_cnt !== "undefined") config.ws_cnt = res.ws_cnt; if (typeof res.ws_cnt !== "undefined") config.ws_cnt = res.ws_cnt;
if (typeof res.ws_rgbo !== "undefined") { if (typeof res.ws_rgbo !== "undefined") {
config.ws_rgbo = res.ws_rgbo; config.ws_rgbo = res.ws_rgbo;
config.enable_rgbw = config.ws_rgbo.includes("W"); config.enable_rgbw = config.ws_rgbo.includes("W");
} }
if (typeof res.ws_pin !== "undefined") config.ws_pin = res.ws_pin; if (typeof res.ws_pin !== "undefined") config.ws_pin = res.ws_pin;
if (typeof res.ws_fxopt !== "undefined") config.ws_fxopt = res.ws_fxopt; if (typeof res.ws_trans !== "undefined") config.ws_trans = res.ws_trans;
if (typeof res.transEffect !== "undefined") config.transitionEffects = res.transEffect;
} }
} else { } else {
console.error(e); console.error(e);
@@ -1567,9 +1628,9 @@ function getConfig() {
} else { } else {
document.getElementById("white").parentNode.className = "hidden"; document.getElementById("white").parentNode.className = "hidden";
white.value = 0; white.value = 0;
data.color.w = 0; segstate.color.w = 0;
data.color.w2 = 0; segstate.color.w2 = 0;
data.color.w3 = 0; segstate.color.w3 = 0;
} }
}); });
} }
@@ -1600,11 +1661,11 @@ function showModes(mode, index) {
document.getElementById("modes").appendChild(div); document.getElementById("modes").appendChild(div);
} }
function readSettings() { function readSettings() {
document.getElementById("percentage").innerHTML = "33%"; document.getElementById("percentage").innerHTML = "25%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "33,100"); document.getElementById("percentage-done").setAttribute("stroke-dasharray", "25,100");
document.getElementById("modal-content").innerHTML = language.en.loadSettings; document.getElementById("modal-content").innerHTML = language.en.loadSettings;
xhttp("http://" + host + "/uistate.json", false, function(e) { xhttp("http://" + host + "/uistate.json", false, function(e) {
//console.log("readSettings()", e); console.log("Read Settings: ", e);
tmpsettings = (e && e.substring(0,6) !== "ERROR!") ? JSON.parse(e) : {}; tmpsettings = (e && e.substring(0,6) !== "ERROR!") ? JSON.parse(e) : {};
// Replace default settings with saved ones // Replace default settings with saved ones
for (var set in settings) { for (var set in settings) {
@@ -1612,8 +1673,12 @@ function readSettings() {
if (typeof(tmpsettings[set]) !== "undefined") settings[set] = tmpsettings[set]; if (typeof(tmpsettings[set]) !== "undefined") settings[set] = tmpsettings[set];
} }
applySettings(); applySettings();
if (e && e.substring(0,6) !== "ERROR!") connectAdditionalNodes(); if (e && e.substring(0,6) !== "ERROR!") {
else console.warn("ERROR loading settings", e); connectAdditionalNodes();
} else {
console.warn("ERROR loading settings", e);
saveSettings();
}
}); });
} }
function applySettings() { function applySettings() {
@@ -1678,13 +1743,13 @@ function onSelectColNum(colnum) {
x = document.getElementById("colorSel" + colnum); x = document.getElementById("colorSel" + colnum);
x.className = x.className.replace(/\belevation-3\b/g, "elevation-9"); x.className = x.className.replace(/\belevation-3\b/g, "elevation-9");
// Set ColorPicker and Sliders to selected color // Set ColorPicker and Sliders to selected color
red.value = data.color["r" + (colnum > 1 ? colnum : "")]; red.value = segstate.color["r" + (colnum > 1 ? colnum : "")];
green.value = data.color["g" + (colnum > 1 ? colnum : "")]; green.value = segstate.color["g" + (colnum > 1 ? colnum : "")];
blue.value = data.color["b" + (colnum > 1 ? colnum : "")]; blue.value = segstate.color["b" + (colnum > 1 ? colnum : "")];
white.value = data.color["w" + (colnum > 1 ? colnum : "")]; white.value = segstate.color["w" + (colnum > 1 ? colnum : "")];
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
} }
function initSettings() { function initSettings() {
// Add languages to language select // Add languages to language select
@@ -1736,11 +1801,33 @@ function initSettings() {
config.mqtt_pass = mqtt_pass.value; config.mqtt_pass = mqtt_pass.value;
ws_send("Cmw" + config.mqtt_pass); ws_send("Cmw" + config.mqtt_pass);
}); });
var count = document.getElementById("selectcount"); var selsegment = document.getElementById("selectseg");
count.value = config.ws_cnt; for(var i = 0; i < config.ws_seg; i++) {
count.addEventListener('change', ()=>{ var option = document.createElement("OPTION");
config.ws_cnt = count.value; option.setAttribute("value", i);
ws_send("Csc" + config.ws_cnt); option.innerHTML = i;
selsegment.appendChild(option);
}
selsegment.value = state.segment;
selsegment.addEventListener('change', ()=>{
state.segment = selsegment.value;
ws_send("Ss" + state.segment);
});
var num_segments = document.getElementById("selectsegcnt");
num_segments.value = config.ws_seg;
num_segments.addEventListener('change', ()=>{
config.ws_seg = num_segments.value;
ws_send("Css" + config.ws_seg);
while (selsegment.firstChild) {
selsegment.removeChild(selsegment.firstChild);
}
for(var i = 0; i < config.ws_seg; i++) {
var option = document.createElement("OPTION");
option.setAttribute("value", i);
option.innerHTML = i;
selsegment.appendChild(option);
}
selsegment.value = state.segment;
}); });
var pin = document.getElementById("selectpin"); var pin = document.getElementById("selectpin");
pin.value = config.ws_pin; pin.value = config.ws_pin;
@@ -1760,6 +1847,28 @@ function initSettings() {
config.ws_rgbo = rgbo.value; config.ws_rgbo = rgbo.value;
ws_send("Csr" + config.ws_rgbo); ws_send("Csr" + config.ws_rgbo);
}); });
var start = document.getElementById("segstart");
start.setAttribute("max",config.ws_cnt-1);
start.value = segstate.start;
start.addEventListener('change', ()=>{
segstate.start = start.value;
ws_send("S[" + segstate.start);
});
var stop = document.getElementById("segstop");
stop.setAttribute("max",config.ws_cnt-1);
stop.value = segstate.stop;
stop.addEventListener('change', ()=>{
segstate.stop = stop.value;
ws_send("S]" + segstate.stop);
});
var count = document.getElementById("selectcount");
count.value = config.ws_cnt;
count.addEventListener('change', ()=>{
config.ws_cnt = count.value;
ws_send("Csc" + config.ws_cnt);
start.setAttribute("max",config.ws_cnt-1);
stop.setAttribute("max",config.ws_cnt-1);
});
var optrev = document.getElementById("selectoptrev"); var optrev = document.getElementById("selectoptrev");
for (var code in selectoptrev) { for (var code in selectoptrev) {
var option = document.createElement("OPTION"); var option = document.createElement("OPTION");
@@ -1767,10 +1876,10 @@ function initSettings() {
option.innerHTML = selectoptrev[code]; option.innerHTML = selectoptrev[code];
optrev.appendChild(option); optrev.appendChild(option);
} }
optrev.value = (config.ws_fxopt & 128); optrev.value = (segstate.ws_fxopt & 128);
optrev.addEventListener('change', ()=>{ optrev.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value; segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt); ws_send("So" + segstate.ws_fxopt);
}); });
var optfade = document.getElementById("selectoptfade"); var optfade = document.getElementById("selectoptfade");
for (var code in selectoptfade) { for (var code in selectoptfade) {
@@ -1779,10 +1888,10 @@ function initSettings() {
option.innerHTML = selectoptfade[code]; option.innerHTML = selectoptfade[code];
optfade.appendChild(option); optfade.appendChild(option);
} }
optfade.value = (config.ws_fxopt & 112); optfade.value = (segstate.ws_fxopt & 112);
optfade.addEventListener('change', ()=>{ optfade.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value; segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt); ws_send("So" + segstate.ws_fxopt);
}); });
var optgamma = document.getElementById("selectoptgamma"); var optgamma = document.getElementById("selectoptgamma");
for (var code in selectoptgamma) { for (var code in selectoptgamma) {
@@ -1791,10 +1900,10 @@ function initSettings() {
option.innerHTML = selectoptgamma[code]; option.innerHTML = selectoptgamma[code];
optgamma.appendChild(option); optgamma.appendChild(option);
} }
optgamma.value = (config.ws_fxopt & 8); optgamma.value = (segstate.ws_fxopt & 8);
optgamma.addEventListener('change', ()=>{ optgamma.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value; segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt); ws_send("So" + segstate.ws_fxopt);
}); });
var optsize = document.getElementById("selectoptsize"); var optsize = document.getElementById("selectoptsize");
for (var code in selectoptsize) { for (var code in selectoptsize) {
@@ -1803,10 +1912,10 @@ function initSettings() {
option.innerHTML = selectoptsize[code]; option.innerHTML = selectoptsize[code];
optsize.appendChild(option); optsize.appendChild(option);
} }
optsize.value = (config.ws_fxopt & 6) optsize.value = (segstate.ws_fxopt & 6)
optsize.addEventListener('change', ()=>{ optsize.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value; segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt); ws_send("So" + segstate.ws_fxopt);
}); });
slavenodes.value = settings.slave_nodes; slavenodes.value = settings.slave_nodes;
lang.addEventListener('change', ()=>{ lang.addEventListener('change', ()=>{
@@ -1820,9 +1929,9 @@ function initSettings() {
redrawColorPicker(); redrawColorPicker();
}); });
var settransitionEffects = document.getElementById("set-transitionEffects"); var settransitionEffects = document.getElementById("set-transitionEffects");
settransitionEffects.checked = config.transitionEffects; settransitionEffects.checked = config.ws_trans;
settransitionEffects.addEventListener('change', ()=>{ settransitionEffects.addEventListener('change', ()=>{
config.transitionEffects = settransitionEffects.checked; config.ws_trans = settransitionEffects.checked;
if (settransitionEffects.checked) { if (settransitionEffects.checked) {
document.getElementById("settransitionEffectsbgcolor").style.backgroundColor = settings.theme_btn; document.getElementById("settransitionEffectsbgcolor").style.backgroundColor = settings.theme_btn;
ws_send("Ce1"); ws_send("Ce1");
@@ -1855,6 +1964,7 @@ function initSettings() {
settings.theme_back = colback.value; settings.theme_back = colback.value;
document.getElementById("container").style.backgroundColor = settings.theme_back; document.getElementById("container").style.backgroundColor = settings.theme_back;
document.getElementById("language").style.backgroundColor = settings.theme_back; document.getElementById("language").style.backgroundColor = settings.theme_back;
document.getElementById("selectseg").style.backgroundColor = settings.theme_back;
document.getElementById("selectrgbo").style.backgroundColor = settings.theme_back; document.getElementById("selectrgbo").style.backgroundColor = settings.theme_back;
document.getElementById("selectoptrev").style.backgroundColor = settings.theme_back; document.getElementById("selectoptrev").style.backgroundColor = settings.theme_back;
document.getElementById("selectoptfade").style.backgroundColor = settings.theme_back; document.getElementById("selectoptfade").style.backgroundColor = settings.theme_back;
@@ -1867,6 +1977,7 @@ function initSettings() {
for (var i = 0; i < icons.length; i++) { for (var i = 0; i < icons.length; i++) {
icons[i].style.color = (yiq >= 125) ? '#222' : '#EEE'; icons[i].style.color = (yiq >= 125) ? '#222' : '#EEE';
} }
document.getElementById("selectSegLbl").style.color = (yiq >= 125) ? '#111' : '#EEE';
document.getElementById("wsmessageLbl").style.color = (yiq >= 125) ? '#111' : '#EEE'; document.getElementById("wsmessageLbl").style.color = (yiq >= 125) ? '#111' : '#EEE';
document.getElementById("redNum").style.color = (yiq >= 125) ? '#111' : '#EEE'; document.getElementById("redNum").style.color = (yiq >= 125) ? '#111' : '#EEE';
document.getElementById("greenNum").style.color = (yiq >= 125) ? '#111' : '#EEE'; document.getElementById("greenNum").style.color = (yiq >= 125) ? '#111' : '#EEE';
@@ -2018,8 +2129,8 @@ function ws_reconnect() {
function ws_connect() { function ws_connect() {
data.connection = new ReconnectingWebSocket(ws_url, "arduino", ws_options); data.connection = new ReconnectingWebSocket(ws_url, "arduino", ws_options);
document.getElementById("percentage").innerHTML = "67%"; document.getElementById("percentage").innerHTML = "75%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "67,100"); document.getElementById("percentage-done").setAttribute("stroke-dasharray", "75,100");
document.getElementById("modal-content").innerHTML = language[settings.lang].loadWebsock; document.getElementById("modal-content").innerHTML = language[settings.lang].loadWebsock;
// When the connection is open, send some data to the server // When the connection is open, send some data to the server
@@ -2031,12 +2142,12 @@ function ws_connect() {
con.className = "hidden"; con.className = "hidden";
con = document.getElementById("connected"); con = document.getElementById("connected");
con.className = con.className = ""; con.className = con.className = "";
document.getElementById("percentage").innerHTML = "100%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "100,100");
document.getElementById("modal-content").innerHTML = language[settings.lang].loadReady;
//setTimeout(function() { ws_send("$"); }, 2000); //setTimeout(function() { ws_send("$"); }, 2000);
//setTimeout(function() { ws_send("C"); }, 3000); //setTimeout(function() { ws_send("C"); }, 3000);
//setTimeout(function() { ws_send("~"); }, 4000); //setTimeout(function() { ws_send("~"); }, 4000);
document.getElementById("percentage").innerHTML = "100%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "100,100");
document.getElementById("modal-content").innerHTML = language[settings.lang].loadReady;
}; };
// When the connection is open, send some data to the server // When the connection is open, send some data to the server
@@ -2069,53 +2180,56 @@ function ws_connect() {
// document.getElementById('modal').style.display = "none"; // document.getElementById('modal').style.display = "none";
// console.log("res", res); // console.log("res", res);
if (res) { if (res) {
// Status starts here if (typeof res.segment !== "undefined") { state.segment= res.segment; document.getElementById("selectseg").value = state.segment; }
if (typeof res.mode !== "undefined") data.mode = res.mode; if (typeof res.mode !== "undefined") { state.mode = res.mode; }
if (typeof res.ws2812fx_mode !== "undefined") data.ws2812fx_mode = res.ws2812fx_mode;
if (typeof res.speed !== "undefined") {
data.speed = res.speed;
// init SliderVals
speed.value = res.speed;
}
if (typeof res.brightness !== "undefined") { if (typeof res.brightness !== "undefined") {
data.brightness = res.brightness; state.brightness = res.brightness;
// init ColorSliderVals // init ColorSliderVals
bright.value = res.brightness; bright.value = res.brightness;
} }
// Segment Status starts here
if (typeof res.start !== "undefined") { segstate.start= res.start; document.getElementById("segstart").value = segstate.start; }
if (typeof res.stop !== "undefined") { segstate.stop = res.stop; document.getElementById("segstop").value = segstate.stop; }
if (typeof res.fx_mode !== "undefined") { segstate.mode = res.fx_mode; }
if (typeof res.speed !== "undefined") {
segstate.speed = res.speed;
// init SliderVals
speed.value = res.speed;
}
if (typeof res.color !== "undefined") { if (typeof res.color !== "undefined") {
data.color.w = res.color[0]; segstate.color.w = res.color[0];
data.color.r = res.color[1]; segstate.color.r = res.color[1];
data.color.g = res.color[2]; segstate.color.g = res.color[2];
data.color.b = res.color[3]; segstate.color.b = res.color[3];
data.color.hex = rgbToHex([res.color[0], res.color[1], res.color[2], res.color[3]]); segstate.color.hex = rgbToHex([res.color[0], res.color[1], res.color[2], res.color[3]]);
data.color.w2 = res.color[4]; segstate.color.w2 = res.color[4];
data.color.r2 = res.color[5]; segstate.color.r2 = res.color[5];
data.color.g2 = res.color[6]; segstate.color.g2 = res.color[6];
data.color.b2 = res.color[7]; segstate.color.b2 = res.color[7];
data.color.hex2 = rgbToHex([res.color[4], res.color[5], res.color[6], res.color[7]]); segstate.color.hex2 = rgbToHex([res.color[4], res.color[5], res.color[6], res.color[7]]);
data.color.w3 = res.color[8]; segstate.color.w3 = res.color[8];
data.color.r3 = res.color[9]; segstate.color.r3 = res.color[9];
data.color.g3 = res.color[10]; segstate.color.g3 = res.color[10];
data.color.b3 = res.color[11]; segstate.color.b3 = res.color[11];
data.color.hex3 = rgbToHex([res.color[8], res.color[9], res.color[10], res.color[11]]); segstate.color.hex3 = rgbToHex([res.color[8], res.color[9], res.color[10], res.color[11]]);
// init ColorSliderVals // init ColorSliderVals
if (data.color_num === 1) { if (data.color_num === 1) {
red.value = data.color.r; red.value = segstate.color.r;
green.value = data.color.g; green.value = segstate.color.g;
blue.value = data.color.b; blue.value = segstate.color.b;
white.value = data.color.w; white.value = segstate.color.w;
} }
if (data.color_num === 2) { if (data.color_num === 2) {
red.value = data.color.r2; red.value = segstate.color.r2;
green.value = data.color.g2; green.value = segstate.color.g2;
blue.value = data.color.b2; blue.value = segstate.color.b2;
white.value = data.color.w2; white.value = segstate.color.w2;
} }
if (data.color_num === 3) { if (data.color_num === 3) {
red.value = data.color.r3; red.value = segstate.color.r3;
green.value = data.color.g3; green.value = segstate.color.g3;
blue.value = data.color.b3; blue.value = segstate.color.b3;
white.value = data.color.w3; white.value = segstate.color.w3;
} }
} }
// Config starts here // Config starts here
@@ -2124,6 +2238,7 @@ function ws_connect() {
if (typeof res.mqtt_port !== "undefined") { config.mqtt_port = res.mqtt_port; document.getElementById("mqtt_port").value = config.mqtt_port; } if (typeof res.mqtt_port !== "undefined") { config.mqtt_port = res.mqtt_port; document.getElementById("mqtt_port").value = config.mqtt_port; }
if (typeof res.mqtt_user !== "undefined") { config.mqtt_user = res.mqtt_user; document.getElementById("mqtt_user").value = config.mqtt_user; } if (typeof res.mqtt_user !== "undefined") { config.mqtt_user = res.mqtt_user; document.getElementById("mqtt_user").value = config.mqtt_user; }
if (typeof res.mqtt_pass !== "undefined") { config.mqtt_pass = res.mqtt_pass; document.getElementById("mqtt_pass").value = config.mqtt_pass; } if (typeof res.mqtt_pass !== "undefined") { config.mqtt_pass = res.mqtt_pass; document.getElementById("mqtt_pass").value = config.mqtt_pass; }
if (typeof res.ws_seg !== "undefined") { config.ws_seg = res.ws_seg; document.getElementById("selectsegcnt").value = config.ws_seg; }
if (typeof res.ws_cnt !== "undefined") { config.ws_cnt = res.ws_cnt; document.getElementById("selectcount").value = config.ws_cnt; } if (typeof res.ws_cnt !== "undefined") { config.ws_cnt = res.ws_cnt; document.getElementById("selectcount").value = config.ws_cnt; }
if (typeof res.ws_rgbo !== "undefined") { if (typeof res.ws_rgbo !== "undefined") {
config.ws_rgbo = res.ws_rgbo; config.ws_rgbo = res.ws_rgbo;
@@ -2134,19 +2249,20 @@ function ws_connect() {
} else { } else {
document.getElementById("white").parentNode.className = "hidden"; document.getElementById("white").parentNode.className = "hidden";
white.value = 0; white.value = 0;
data.color.w = 0; segstate.color.w = 0;
data.color.w2 = 0; segstate.color.w2 = 0;
data.color.w3 = 0; segstate.color.w3 = 0;
} }
} }
if (typeof res.ws_pin !== "undefined") { config.ws_pin = res.ws_pin; document.getElementById("selectpin").value = config.ws_pin; } if (typeof res.ws_pin !== "undefined") { config.ws_pin = res.ws_pin; document.getElementById("selectpin").value = config.ws_pin; }
if (typeof res.ws_trans !== "undefined") { config.ws_trans = res.ws_trans; document.getElementById("set-transitionEffects").value = config.ws_trans; }
if (typeof res.ws_fxopt !== "undefined") { if (typeof res.ws_fxopt !== "undefined") {
config.ws_fxopt = res.ws_fxopt; segstate.ws_fxopt = res.ws_fxopt;
document.getElementById("selectoptrev").value = (config.ws_fxopt & 128); document.getElementById("selectoptrev").value = (segstate.ws_fxopt & 128);
document.getElementById("selectoptfade").value = (config.ws_fxopt & 112); document.getElementById("selectoptfade").value = (segstate.ws_fxopt & 112);
document.getElementById("selectoptgamma").value = (config.ws_fxopt & 8); document.getElementById("selectoptgamma").value = (segstate.ws_fxopt & 8);
document.getElementById("selectoptsize").value = (config.ws_fxopt & 6); document.getElementById("selectoptsize").value = (segstate.ws_fxopt & 6);
} }
// Modes starts here // Modes starts here
if (typeof res[0] !== "undefined") { if (typeof res[0] !== "undefined") {
@@ -2157,18 +2273,22 @@ function ws_connect() {
}); });
} }
// init Color Vals // init Color Vals
colorNumrVals(); colorNumVals();
initSliderColors(); initSliderColors();
// init Change Range Val // init Change Range Val
changeRangeNumVal(); changeRangeNumVal();
// init Colors controls // init Colors controls
// init display Colors // init display Colors
displayColors(true); displayColors(true);
console.log("displayColors finished!");
select_active_button(); select_active_button();
console.log("select_active_button finished!");
} }
if (data.init === true) { console.log("data.init: ", data.init);
if (data.init == true) {
console.log("Initializing...");
// Set selected mode button // Set selected mode button
//document.getElementById(data.ws2812fx_mode).style.backgroundColor = settings.theme_btnsel; //document.getElementById(segstate.mode).style.backgroundColor = settings.theme_btnsel;
// Close Loading Modal // Close Loading Modal
setTimeout(() => { setTimeout(() => {
document.getElementById('modal').style.display = "none"; document.getElementById('modal').style.display = "none";
@@ -2212,38 +2332,45 @@ function select_active_button() {
for (i = 0; i < btns.length; i++) { for (i = 0; i < btns.length; i++) {
btns[i].style.backgroundColor = settings.theme_btn; btns[i].style.backgroundColor = settings.theme_btn;
} }
if (data.mode != 1 || (data.mode === 1 && data.ws2812fx_mode !== 57)) { // CUSTOM WS MODE if (state.mode != 1 || (state.mode == 1 && segstate.mode != 57)) { // CUSTOM WS MODE
wsmess = document.getElementById("message"); wsmess = document.getElementById("message");
var arr = wsmess.className.split(" "); var arr = wsmess.className.split(" ");
if (arr.indexOf("hidden") === -1) { if (arr.indexOf("hidden") === -1) {
wsmess.className += " hidden"; wsmess.className += " hidden";
} }
segments = document.getElementById("segments");
segments.className = segments.className.replace(/\b hidden\b/g, "");
} }
if (data.mode >= 1) { if (state.mode >= 1) {
document.getElementById(data.ws2812fx_mode).style.backgroundColor = settings.theme_btnsel; document.getElementById(segstate.mode).style.backgroundColor = settings.theme_btnsel;
if (data.ws2812fx_mode === 56) { // AUTOPLAY if (segstate.mode == 56) { // AUTOPLAY
disable_modebuttons(false); disable_modebuttons(false);
disable_color_selection(true); disable_color_selection(true);
disable_bright_selection(false); disable_bright_selection(false);
disable_speed_selection(true); disable_speed_selection(true);
} else if (data.ws2812fx_mode === 57) { //CUSTOM_WS } else if (segstate.mode == 57) { //CUSTOM_WS
wsmess = document.getElementById("message"); wsmess = document.getElementById("message");
wsmess.className = wsmess.className.replace(/\b hidden\b/g, ""); wsmess.className = wsmess.className.replace(/\b hidden\b/g, "");
sements = document.getElementById("segments");
var arr = segments.className.split(" ");
if (arr.indexOf("hidden") === -1) {
segments.className += " hidden";
}
disable_modebuttons(false); disable_modebuttons(false);
disable_color_selection(true); disable_color_selection(true);
disable_bright_selection(false); disable_bright_selection(false);
disable_speed_selection(true); disable_speed_selection(true);
} else if (data.ws2812fx_mode === 58) { //TV } else if (segstate.mode == 58) { //TV
disable_modebuttons(false); disable_modebuttons(false);
disable_color_selection(true); disable_color_selection(true);
disable_bright_selection(false); disable_bright_selection(false);
disable_speed_selection(false); disable_speed_selection(false);
} else if (data.ws2812fx_mode === 59) { //E1.31 } else if (segstate.mode == 59) { //E1.31
disable_modebuttons(false); disable_modebuttons(false);
disable_color_selection(true); disable_color_selection(true);
disable_bright_selection(false); disable_bright_selection(false);
disable_speed_selection(true); disable_speed_selection(true);
} else if (data.ws2812fx_mode === 60) { //Fire2012 } else if (segstate.mode == 60) { //Fire2012
disable_modebuttons(false); disable_modebuttons(false);
disable_color_selection(true); disable_color_selection(true);
disable_bright_selection(false); disable_bright_selection(false);
@@ -2254,7 +2381,7 @@ function select_active_button() {
disable_bright_selection(false); disable_bright_selection(false);
disable_speed_selection(false); disable_speed_selection(false);
} }
} else if (data.mode === 0) { } else if (state.mode == 0) {
document.getElementById("off").style.backgroundColor = settings.theme_btnsel; document.getElementById("off").style.backgroundColor = settings.theme_btnsel;
disable_modebuttons(false); disable_modebuttons(false);
disable_color_selection(true); disable_color_selection(true);
@@ -2282,32 +2409,32 @@ function disable_modebuttons(status) {
function set_mode(mode_id) { function set_mode(mode_id) {
if (Number.isInteger(mode_id)) { if (Number.isInteger(mode_id)) {
data.mode = 1; state.mode = 1;
data.ws2812fx_mode = mode_id; segstate.mode = mode_id;
} else { } else {
// For named modes // For named modes
if (mode_id == "off") { if (mode_id == "off") {
data.mode = 0; state.mode = 0;
} }
} }
select_active_button(); select_active_button();
ws_send("/" + mode_id); ws_send("/" + mode_id);
} }
function set_speed() { function set_speed() {
ws_send("?" + data.speed); ws_send("?" + segstate.speed);
} }
function set_brightness() { function set_brightness() {
ws_send("%" + data.brightness); ws_send("%" + state.brightness);
} }
function set_color() { function set_color() {
if (data.color_num === 1) { if (data.color_num === 1) {
ws_send("#" + rgbToHex([data.color.w, data.color.r, data.color.g, data.color.b])); ws_send("#" + rgbToHex([segstate.color.w, segstate.color.r, segstate.color.g, segstate.color.b]));
} }
if (data.color_num === 2) { if (data.color_num === 2) {
ws_send("##" + rgbToHex([data.color.w2, data.color.r2, data.color.g2, data.color.b2])); ws_send("##" + rgbToHex([segstate.color.w2, segstate.color.r2, segstate.color.g2, segstate.color.b2]));
} }
if (data.color_num === 3) { if (data.color_num === 3) {
ws_send("###" + rgbToHex([data.color.w3, data.color.r3, data.color.g3, data.color.b3])); ws_send("###" + rgbToHex([segstate.color.w3, segstate.color.r3, segstate.color.g3, segstate.color.b3]));
} }
} }
@@ -2345,11 +2472,11 @@ function onSelectColor(event) {
var color = context.getImageData(pos.x, pos.y, 1, 1).data; var color = context.getImageData(pos.x, pos.y, 1, 1).data;
var hex_color = rgbToHex(color); var hex_color = rgbToHex(color);
var colnum = (data.color_num === 1) ? "" : data.color_num; var colnum = (data.color_num === 1) ? "" : data.color_num;
data.color["hex" + colnum] = hex_color; segstate.color["hex" + colnum] = hex_color;
data.color["r" + colnum] = color[0]; segstate.color["r" + colnum] = color[0];
data.color["g" + colnum] = color[1]; segstate.color["g" + colnum] = color[1];
data.color["b" + colnum] = color[2]; segstate.color["b" + colnum] = color[2];
data.color["w" + colnum] = 0; segstate.color["w" + colnum] = 0;
red.value = color[0]; red.value = color[0];
green.value = color[1]; green.value = color[1];
blue.value = color[2]; blue.value = color[2];
@@ -2357,7 +2484,7 @@ function onSelectColor(event) {
displayColors(); displayColors();
initSliderColors(); initSliderColors();
changeRangeNumVal(); changeRangeNumVal();
colorNumrVals(); colorNumVals();
} }
} }
function redrawColorPicker() { function redrawColorPicker() {
@@ -2525,13 +2652,11 @@ document.addEventListener("DOMContentLoaded", function(event) {
getModes(); getModes();
readSettings(); readSettings();
ws_connect(); ws_connect();
ws_send("$") ws_send("$");
document.getElementById("modal-content").innerHTML = language.en.loadModes;
//ws_send("C"); //ws_send("C");
getConfig(); getConfig();
canvas.width = 400; canvas.width = 400;
canvas.height = 400; canvas.height = 400;
redrawColorPicker(); redrawColorPicker();
}); });
</script> </script>
Binary file not shown.