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
+168 -271
View File
@@ -1,4 +1,8 @@
#include "definitions.h"
// ***************************************************************************
// Load library "ticker" for blinking status led, mqtt send and save state
// ***************************************************************************
#include <Ticker.h>
#include "version.h"
// ***************************************************************************
@@ -10,13 +14,10 @@
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
#include <FS.h>
#include <WiFiClient.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 <WebSocketsServer.h>
@@ -28,8 +29,6 @@
GY33_MCU tcs;
#endif
#include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson
// MQTT
#if defined(ENABLE_MQTT)
#if ENABLE_MQTT == 0
@@ -50,12 +49,11 @@
AsyncMqttClient * mqtt_client;
WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler;
Ticker mqttReconnectTimer;
Ticker wifiReconnectTimer;
#endif
#endif
#if defined(ARDUINOJSON_VERSION)
#if !(ARDUINOJSON_VERSION_MAJOR == 6 and ARDUINOJSON_VERSION_MINOR >= 8)
#error "Install ArduinoJson v6.8.x or higher"
#if defined(ENABLE_HOMEASSISTANT)
Ticker ha_send_data;
#endif
#endif
@@ -169,21 +167,9 @@ WS2812FX * strip = NULL;
}
#endif
// ***************************************************************************
// Load library "ticker" for blinking status led, mqtt send and save state
// ***************************************************************************
#include <Ticker.h>
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() {
//toggle state
@@ -196,9 +182,6 @@ void tick() {
decode_results results;
#endif
Ticker settings_save_state;
Ticker settings_save_conf;
// ***************************************************************************
// Saved state handling in WifiManager
// ***************************************************************************
@@ -245,90 +228,22 @@ void saveConfigCallback () {
// ***************************************************************************
#include "spiffs_webserver.h"
// ***************************************************************************
// Include: Request handlers
// ***************************************************************************
#include "request_handlers.h"
// ***************************************************************************
// Include: Custom animations
// ***************************************************************************
#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 ){
DBG_OUTPUT_PORT.println("Initializing strip!");
/*#if defined(USE_WS2812FX_DMA)
if (dma != NULL) {
delete(dma);
}
#endif*/
if (strip != NULL) {
delete(strip);
WS2812FXStripSettings.stripSize = stripSize;
strcpy(WS2812FXStripSettings.RGBOrder, RGBOrder);
WS2812FXStripSettings.pin = pin;
WS2812FXStripSettings.fxoptions = fxoptions;
}
// ***************************************************************************
// Include: helper functions
// ***************************************************************************
#include "helper_functions.h"
if (ledstates != NULL) {
delete(ledstates);
}
ledstates = new uint8_t [WS2812FXStripSettings.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
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
}
// ***************************************************************************
// Include: other functions
// ***************************************************************************
#include "json_functions.h"
#include "filesystem_functions.h"
#include "request_handlers.h"
#if defined(ENABLE_MQTT)
void initMqtt() {
@@ -394,9 +309,6 @@ void setup() {
delay(500);
DBG_OUTPUT_PORT.println("");
DBG_OUTPUT_PORT.println("Starting...Main Setup");
#if ENABLE_STATE_SAVE == 0
EEPROM.begin(512);
#endif
// set builtin led pin as output
pinMode(LED_BUILTIN, OUTPUT);
// button pin setup
@@ -415,6 +327,10 @@ void setup() {
}
#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
ticker.attach(0.5, tick);
@@ -444,37 +360,30 @@ void setup() {
#if defined(ENABLE_STATE_SAVE)
//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!");
delay(250);
(readStateFS()) ? DBG_OUTPUT_PORT.println("Strip state config FS read Success!") : DBG_OUTPUT_PORT.println("Strip state config FS read failure!");
#endif
#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
(readConfigFS()) ? DBG_OUTPUT_PORT.println("WiFiManager config FS read success!"): DBG_OUTPUT_PORT.println("WiFiManager config FS Read failure!");
delay(250);
(readStateFS()) ? DBG_OUTPUT_PORT.println("Strip state config FS read Success!") : DBG_OUTPUT_PORT.println("Strip state config FS read failure!");
char _stripSize[6], _fx_options[5], _rgbOrder[5]; //needed tempararily for WiFiManager Settings
WiFiManagerParameter custom_hostname("hostname", "Hostname", HOSTNAME, 64, " maxlength=64");
#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");
sprintf(tmp_mqtt_port, "%d", mqtt_port);
WiFiManagerParameter custom_mqtt_port("port", "MQTT port", tmp_mqtt_port, 5, " maxlength=5 type=\"number\"");
sprintf(_mqtt_port, "%d", mqtt_port);
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_pass("pass", "MQTT pass", mqtt_pass, 32, " maxlength=32 type=\"password\"");
#endif
sprintf(tmp_strip_size, "%d", WS2812FXStripSettings.stripSize);
WiFiManagerParameter custom_strip_size("strip_size", "Number of LEDs", tmp_strip_size, 4, " maxlength=4 type=\"number\"");
sprintf(_stripSize, "%d", Config.stripSize);
WiFiManagerParameter custom_strip_size("strip_size", "Number of LEDs", _stripSize, 4, " maxlength=4 type=\"number\"");
#if !defined(USE_WS2812FX_DMA)
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\"");
#endif
sprintf(tmp_rgbOrder, "%s", WS2812FXStripSettings.RGBOrder);
WiFiManagerParameter custom_rgbOrder("rgbOrder", "RGBOrder", tmp_rgbOrder, 4, " maxlength=4");
sprintf(tmp_fxoptions, "%d", WS2812FXStripSettings.fxoptions);
WiFiManagerParameter custom_fxoptions("fxoptions", "fxOptions", tmp_fxoptions, 3, " maxlength=3");
sprintf(_rgbOrder, "%s", Config.RGBOrder);
WiFiManagerParameter custom_rgbOrder("rgbOrder", "RGBOrder", _rgbOrder, 4, " maxlength=4");
sprintf(_fx_options, "%d", segState.options);
WiFiManagerParameter custom_fxoptions("fxoptions", "fxOptions", _fx_options, 3, " maxlength=3");
#endif
@@ -538,31 +447,16 @@ void setup() {
strcpy(mqtt_user, custom_mqtt_user.getValue());
strcpy(mqtt_pass, custom_mqtt_pass.getValue());
#endif
strcpy(tmp_strip_size, custom_strip_size.getValue());
WS2812FXStripSettings.stripSize = constrain(atoi(custom_strip_size.getValue()), 1, MAXLEDS);
strcpy(_stripSize, custom_strip_size.getValue());
Config.stripSize = constrain(atoi(custom_strip_size.getValue()), 1, MAXLEDS);
#if !defined(USE_WS2812FX_DMA)
checkPin(atoi(custom_led_pin.getValue()));
#endif
strcpy(tmp_rgbOrder, custom_rgbOrder.getValue());
checkRGBOrder(tmp_rgbOrder);
WS2812FXStripSettings.fxoptions = atoi(custom_fxoptions.getValue());
strcpy(_rgbOrder, custom_rgbOrder.getValue());
checkRGBOrder(_rgbOrder);
segState.options = atoi(custom_fxoptions.getValue());
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!");
#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
(writeConfigFS(updateConfig)) ? DBG_OUTPUT_PORT.println("WiFiManager config FS Save success!"): DBG_OUTPUT_PORT.println("WiFiManager config FS Save failure!");
}
#endif
@@ -641,11 +535,11 @@ void setup() {
DBG_OUTPUT_PORT.print("Use http://");
DBG_OUTPUT_PORT.print(HOSTNAME);
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(WiFi.localIP());
DBG_OUTPUT_PORT.println("/upload to upload the webpages first.");
#endif
DBG_OUTPUT_PORT.println("");
// ***************************************************************************
@@ -671,9 +565,8 @@ void setup() {
#if defined(ENABLE_REMOTE)
irrecv.enableIRIn(); // Start the receiver
#endif
ws2812fx_speed_actual = ws2812fx_speed;
brightness_trans = brightness;
memcpy(hex_colors, hex_colors_trans, sizeof(hex_colors_trans));
fx_speed = segState.speed[State.segment];
brightness_trans = State.brightness;
initStrip();
strip->setBrightness(0);
DBG_OUTPUT_PORT.println("finished Main Setup!");
@@ -734,94 +627,112 @@ void loop() {
// ***************************************************************************
// 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()) {
strip->strip_off(); // Workaround: to be shure,
delay(10); // that strip is really off. Sometimes strip->stop isn't enought
strip->stop(); // should clear memory
autoCount = 0;
autoDelay = 0;
for (uint8_t i = 0; i < Config.segments; i++) {
autoCount[i] = 0;
autoDelay[i] = 0;
}
} else {
if (prevmode != mode) { // Start temporarily to clear strip
if (prevmode != State.mode) { // Start temporarily to clear strip
strip->start();
strip->strip_off(); // Workaround: to be shure,
delay(10); // that strip is really off. Sometimes strip->stop isn't enought
strip->stop(); // should clear memory
autoCount = 0;
autoDelay = 0;
for (uint8_t i = 0; i < Config.segments; i++) {
autoCount[i] = 0;
autoDelay[i] = 0;
}
}
}
}
if (mode == OFF) {
if (prevmode != mode) {
if (State.mode == OFF) {
if (prevmode != State.mode) {
#if defined(ENABLE_MQTT)
snprintf(mqtt_buf, sizeof(mqtt_buf), "OK =off", "");
#endif
if (transEffect) {
#if defined(POWER_SUPPLY)
digitalWrite(POWER_SUPPLY, LOW); // power off -> external power supply
#endif
if (Config.transEffect) {
brightness_trans = 0;
}
}
}
if (mode == INIT_STRIP) {
mode = prevmode;
strip->strip_off();
delay(10);
if(strip->isRunning()) strip->stop();
initStrip();
prevmode = INIT_STRIP;
#if defined(POWER_SUPPLY)
if (State.mode != OFF) {
if (prevmode != State.mode) {digitalWrite(POWER_SUPPLY, HIGH); } // power on -> external power supply
}
#endif
if (mode == SET) {
mode = HOLD;
// Mode
if (ws2812fx_mode != strip->getMode(selected_segment)) { // SET_MODE
if (State.mode == SET) {
State.mode = HOLD;
// Segment
if (prevsegment != State.segment) {
#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
strip->strip_off();
autoCount = 0;
autoDelay = 0;
strip->setMode(selected_segment, ws2812fx_mode);
autoCount[State.segment] = 0;
autoDelay[State.segment] = 0;
//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
/*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
if (strip->getBrightness() != brightness) {
if (strip->getBrightness() != State.brightness) {
#if defined(ENABLE_MQTT)
snprintf(mqtt_buf, sizeof(mqtt_buf), "OK %%%i", brightness);
snprintf(mqtt_buf, sizeof(mqtt_buf), "OK %%%i", State.brightness);
#endif
brightness_trans = brightness;
brightness_trans = State.brightness;
}
// Speed
if (ws2812fx_speed_actual != ws2812fx_speed) {
if (fx_speed != segState.speed[State.segment]) {
#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
}
prevmode = SET;
strip->trigger();
}
if (prevmode != mode) {
convertColors();
if (memcmp(hex_colors_trans, strip->getColors(selected_segment), sizeof(hex_colors_trans)) != 0) {
DBG_OUTPUT_PORT.println("Colors not equal!");
convertColorsFade();
trans_cnt = 1;
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();
if (memcmp(hexcolors_trans, strip->getColors(prevsegment), sizeof(hexcolors_trans)) != 0) {
DBG_OUTPUT_PORT.println("Color changed!");
trans_cnt_max = convertColorsFade(prevsegment);
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);
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 ENABLE_MQTT == 0
mqtt_client->publish(mqtt_outtopic, mqtt_buf);
@@ -834,102 +745,75 @@ void loop() {
#endif
#endif
}
prevmode = State.mode;
#if defined(ENABLE_STATE_SAVE)
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!");
#endif
#if ENABLE_STATE_SAVE == 0
writeEEPROM(384, 66, last_state); // 384 --> last_state (reserved 66 bytes)
EEPROM.commit();
updateState = false;
settings_save_state.detach();
#endif
(writeStateFS(updateState)) ? DBG_OUTPUT_PORT.println("State FS Save Success!") : DBG_OUTPUT_PORT.println("State FS Save failure!");
}
if (updateSegState) {
(writeSegmentStateFS(updateSegState, prevsegment)) ? DBG_OUTPUT_PORT.println("Segment State FS Save Success!") : DBG_OUTPUT_PORT.println("Segment State FS Save failure!");
}
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!");
#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
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
if (memcmp(hex_colors_trans, strip->getColors(selected_segment), sizeof(hex_colors_trans)) != 0) {
if (transEffect) {
if ((segState.mode[prevsegment] != FX_MODE_CUSTOM_0) && (memcmp(hexcolors_trans, strip->getColors(prevsegment), sizeof(hexcolors_trans)) != 0)) {
if (Config.transEffect) {
if ((trans_cnt > 0) && (trans_cnt < trans_cnt_max)) {
if (colorFadeDelay <= millis()) {
uint32_t hex_colors_actual[3] = {};
hex_colors_actual[0] = trans(hex_colors_trans[0], hex_colors[0], trans_cnt);
hex_colors_actual[1] = trans(hex_colors_trans[1], hex_colors[1], trans_cnt);
hex_colors_actual[2] = trans(hex_colors_trans[2], hex_colors[2], trans_cnt);
strip->setColors(selected_segment, hex_colors_actual);
uint32_t _hexcolors_new[3] = {};
_hexcolors_new[0] = trans(hexcolors_trans[0], strip->getColors(prevsegment)[0], trans_cnt, trans_cnt_max);
_hexcolors_new[1] = trans(hexcolors_trans[1], strip->getColors(prevsegment)[1], trans_cnt, trans_cnt_max);
_hexcolors_new[2] = trans(hexcolors_trans[2], strip->getColors(prevsegment)[2], trans_cnt, trans_cnt_max);
strip->setColors(prevsegment, _hexcolors_new);
trans_cnt++;
colorFadeDelay = millis() + TRANS_COLOR_DELAY;
if (mode == HOLD) strip->trigger();
if (State.mode == HOLD) strip->trigger();
}
} else if (trans_cnt >= trans_cnt_max) {
memcpy(hex_colors, hex_colors_trans, sizeof(hex_colors_trans));
strip->setColors(selected_segment, hex_colors);
if (mode == HOLD) strip->trigger();
trans_cnt = 0;
strip->setColors(prevsegment, hexcolors_trans);
if (State.mode == HOLD) strip->trigger();
DBG_OUTPUT_PORT.println("Color transition finished!");
trans_cnt = 0;
}
} else {
memcpy(hex_colors, hex_colors_trans, sizeof(hex_colors_trans));
strip->setColors(selected_segment, hex_colors);
if (mode == HOLD) strip->trigger();
trans_cnt = 0;
strip->setColors(prevsegment, hexcolors_trans);
if (State.mode == HOLD) strip->trigger();
}
}
// Async speed transition
if (ws2812fx_speed_actual != ws2812fx_speed) {
if (transEffect) {
if ((segState.mode[prevsegment] != FX_MODE_CUSTOM_0) && (fx_speed != segState.speed[prevsegment])) {
if (Config.transEffect) {
//if (true == false) { // disabled for the moment
if (speedFadeDelay <= millis()) {
DBG_OUTPUT_PORT.println("Speed actual: ");
DBG_OUTPUT_PORT.println(ws2812fx_speed_actual);
DBG_OUTPUT_PORT.println(convertSpeed(ws2812fx_speed_actual));
DBG_OUTPUT_PORT.println(unconvertSpeed(convertSpeed(ws2812fx_speed_actual)));
if (ws2812fx_speed_actual < ws2812fx_speed) {
ws2812fx_speed_actual++;
//DBG_OUTPUT_PORT.print("Speed trans actual: ");
if (fx_speed < segState.speed[prevsegment]) {
fx_speed++;
}
if (ws2812fx_speed_actual > ws2812fx_speed) {
ws2812fx_speed_actual--;
if (fx_speed > segState.speed[prevsegment]) {
fx_speed--;
}
//DBG_OUTPUT_PORT.println(fx_speed);
speedFadeDelay = millis() + TRANS_DELAY;
strip->setSpeed(selected_segment, convertSpeed(ws2812fx_speed_actual));
if (mode == HOLD) strip->trigger();
strip->setSpeed(prevsegment, convertSpeed(fx_speed));
if (State.mode == HOLD) strip->trigger();
}
} else {
ws2812fx_speed_actual = ws2812fx_speed;
strip->setSpeed(selected_segment, convertSpeed(ws2812fx_speed_actual));
if (mode == HOLD) strip->trigger();
fx_speed = segState.speed[prevsegment];
//DBG_OUTPUT_PORT.print("Speed actual: ");
strip->setSpeed(prevsegment, convertSpeed(fx_speed));
//DBG_OUTPUT_PORT.println(fx_speed);
if (State.mode == HOLD) strip->trigger();
}
}
// Async brightness transition
if (strip->getBrightness() != brightness_trans) {
if (transEffect) {
if (Config.transEffect) {
if(brightnessFadeDelay <= millis()) {
if (strip->getBrightness() < brightness_trans) {
strip->increaseBrightness(1);
@@ -938,16 +822,29 @@ void loop() {
strip->decreaseBrightness(1);
}
brightnessFadeDelay = millis() + TRANS_DELAY;
//if (mode == HOLD) strip->trigger();
strip->trigger();
if (State.mode == HOLD) strip->trigger();
}
} else {
strip->setBrightness(brightness);
if (mode == HOLD) strip->trigger();
brightness_trans = State.brightness;
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)
handleRemote();
+4
View File
@@ -340,6 +340,10 @@ uint32_t* WS2812FX::getColors(uint8_t seg) {
return _segments[seg].colors;
}
uint8_t WS2812FX::getSegmentIndex(void) {
return _segment_index;
}
WS2812FX::Segment* WS2812FX::getSegment(void) {
return &_segments[_segment_index];
}
+2 -1
View File
@@ -500,7 +500,8 @@ class WS2812FX : public Adafruit_NeoPixel {
getNumSegments(void),
get_random_wheel_index(uint8_t),
getOptions(uint8_t),
getNumBytesPerPixel(void);
getNumBytesPerPixel(void),
getSegmentIndex(void);
uint16_t
random16(void),
+3 -1
View File
@@ -182,7 +182,9 @@
var mkfile = document.createElement("button");
mkfile.innerHTML = '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(){
if (xmlHttp.readyState == 4){
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 class="flex xs12 sm7">
<div class="flex xs12 sm8">
<div class="sliders container">
<div class="color-wrap" style="display:none">
<div id="color-display"></div>
@@ -912,6 +912,13 @@ input[type=number], label{
<input type="number" id="speedNum">
<input value="255" type="range" min="0" max="255" id="speed">
</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="wsmessageLbl" style="text-align: left;"><p>wsMessage</p>
<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 class="layout row wrap">
<div class="flex xs12 sm4"><p>selectCount</p>
<input type="number" min="0" max="65535" id="selectcount" style="border: 2px solid #aaaaaa; border-radius: 6px; width:100%;" />
<div class="flex xs12 sm3"><p>selectSegCnt</p>
<input type="number" min="1" max="9" id="selectsegcnt" style="border: 2px solid #aaaaaa; border-radius: 6px; width:50%;" />
</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>
</div>
<div class="flex xs12 sm4"><p>selectPin</p>
<input type="number" min="0" max="16" id="selectpin" style="border: 2px solid #aaaaaa; border-radius: 6px; width:100%;" />
<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: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 class="layout row wrap">
@@ -1030,6 +1048,7 @@ var language = {
connectError2: " times. Please use the RECONNECT button to try again.",
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)
loadConfig: "Loading configuration ...",
loadWebsock: "Connecting websockets ...",
loadReady: "Ready ...",
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",
not_greater: "cannot enter numbers greater than 255",
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:",
selectLanguage: "Select Language:",
selectHostname: "Hostname:",
@@ -1050,6 +1072,7 @@ var language = {
selectMQTTPort: "and Port:",
selectMQTTUser: "MQTT Username:",
selectMQTTPass: "MQTT Password:",
selectSegCnt: "Number of Segments:",
selectCount: "Strip LED Count:",
selectRGBO: "RGB Order:",
selectPin: "Strip GPIO Pin:",
@@ -1086,6 +1109,7 @@ var language = {
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)
loadSettings: "Instellingen laden...", // This language-string is not translated (settings not loaded yet)
loadConfig: "Configuratie laden ...",
loadWebsock: "Websockets verbinden...",
loadReady: "Klaar...",
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",
not_greater: "Geen nummers hoger dan 255",
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:",
selectLanguage: "Selecteer Taal:",
selectHostname: "Hostname:",
@@ -1106,6 +1133,7 @@ var language = {
selectMQTTPort: "en Port:",
selectMQTTUser: "MQTT gebruikersnaam:",
selectMQTTPass: "MQTT wachtwoord:",
selectSegCnt: "Number of Segments:",
selectCount: "LED nummer:",
selectPin: "Strip GPIO Pin:",
selectRGBO: "RGB Order:",
@@ -1142,6 +1170,7 @@ var language = {
connectError2: " mal versucht. Benutze WIEDER VERBINDEN, um es nochmal zu probieren.",
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)
loadConfig: "Lade Konfiguration ...",
loadWebsock: "Verbinde Websockets ...",
loadReady: "Fertig ...",
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ß",
not_greater: "Akzeptiere keine Nummern größer 255",
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:",
selectLanguage: "Sprache auswählen:",
selectHostname: "Hostname:",
@@ -1162,6 +1194,7 @@ var language = {
selectMQTTPort: "und Port:",
selectMQTTUser: "MQTT Username:",
selectMQTTPass: "MQTT Password:",
selectSegCnt: "Anzahl Segmente:",
selectCount: "Strip LED Anzahl:",
selectRGBO: "RGB Reihenfolge:",
selectPin: "Strip GPIO Pin:",
@@ -1281,19 +1314,31 @@ var config = {
mqtt_port: 0,
mqtt_user: "",
mqtt_pass: "",
ws_seg: 1,
ws_cnt: 0,
ws_rgbo: "",
ws_pin: 0,
ws_fxopt: 0,
enable_rgbw: false,
transitionEffects: true
ws_trans: false,
enable_rgbw: false
};
var data = {
var state = {
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"},
brightness: 192,
speed: 192,
ws2812fx_mode: null,
ws_fxopt: 0
}
var data = {
init: true,
color_num: 1,
modes: [],
connection: null,
@@ -1301,7 +1346,6 @@ var data = {
num_additional_connections: 0,
is_connected: false,
refresh_interval: 0,
init: true,
color_disabled: false
};
var sendIt; // Timer to prevent lots of sending
@@ -1331,17 +1375,17 @@ function displayColors(all = false) {
clearTimeout(sendIt);
sendIt = setTimeout(function() { set_color(); }, 50);
} else {
document.getElementById("colorSel1").style.backgroundColor = `rgb(${data.color.r}, ${data.color.g}, ${data.color.b})`;
document.getElementById("colorHex1").innerHTML = "#" + data.color.hex;
document.getElementById("colorSel2").style.backgroundColor = `rgb(${data.color.r2}, ${data.color.g2}, ${data.color.b2})`;
document.getElementById("colorHex2").innerHTML = "#" + data.color.hex2;
document.getElementById("colorSel3").style.backgroundColor = `rgb(${data.color.r3}, ${data.color.g3}, ${data.color.b3})`;
document.getElementById("colorHex3").innerHTML = "#" + data.color.hex3;
document.getElementById("colorSel1").style.backgroundColor = `rgb(${segstate.color.r}, ${segstate.color.g}, ${segstate.color.b})`;
document.getElementById("colorHex1").innerHTML = "#" + segstate.color.hex;
document.getElementById("colorSel2").style.backgroundColor = `rgb(${segstate.color.r2}, ${segstate.color.g2}, ${segstate.color.b2})`;
document.getElementById("colorHex2").innerHTML = "#" + segstate.color.hex2;
document.getElementById("colorSel3").style.backgroundColor = `rgb(${segstate.color.r3}, ${segstate.color.g3}, ${segstate.color.b3})`;
document.getElementById("colorHex3").innerHTML = "#" + segstate.color.hex3;
}
}
// initial color val numbers when DOM is loaded
function colorNumrVals(){
function colorNumVals(){
redNumVal.value = red.value;
greenNumVal.value = green.value;
blueNumVal.value = blue.value;
@@ -1377,44 +1421,44 @@ function initSliderColors(){
function changeRangeNumVal(){
redNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255
red.value = checkNumVal(redNumVal, red.value);
if (data.color_num === 1) data.color.r = red.value;
if (data.color_num === 2) data.color.r2 = red.value;
if (data.color_num === 3) data.color.r3 = red.value;
red.value = checkNumVal8(redNumVal, red.value);
if (data.color_num === 1) segstate.color.r = red.value;
if (data.color_num === 2) segstate.color.r2 = red.value;
if (data.color_num === 3) segstate.color.r3 = red.value;
initSliderColors();
displayColors();
});
greenNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255
green.value = checkNumVal(greenNumVal, green.value);
if (data.color_num === 1) data.color.g = green.value;
if (data.color_num === 2) data.color.g2 = green.value;
if (data.color_num === 3) data.color.g3 = green.value;
green.value = checkNumVal8(greenNumVal, green.value);
if (data.color_num === 1) segstate.color.g = green.value;
if (data.color_num === 2) segstate.color.g2 = green.value;
if (data.color_num === 3) segstate.color.g3 = green.value;
initSliderColors();
displayColors();
});
blueNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255
blue.value = checkNumVal(blueNumVal, blue.value);
if (data.color_num === 1) data.color.b = blue.value;
if (data.color_num === 2) data.color.b2 = blue.value;
if (data.color_num === 3) data.color.b3 = blue.value;
blue.value = checkNumVal8(blueNumVal, blue.value);
if (data.color_num === 1) segstate.color.b = blue.value;
if (data.color_num === 2) segstate.color.b2 = blue.value;
if (data.color_num === 3) segstate.color.b3 = blue.value;
initSliderColors();
displayColors();
});
whiteNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255
white.value = checkNumVal(whiteNumVal, white.value);
if (data.color_num === 1) data.color.w = white.value;
if (data.color_num === 2) data.color.w2 = white.value;
if (data.color_num === 3) data.color.w3 = white.value;
white.value = checkNumVal8(whiteNumVal, white.value);
if (data.color_num === 1) segstate.color.w = white.value;
if (data.color_num === 2) segstate.color.w2 = white.value;
if (data.color_num === 3) segstate.color.w3 = white.value;
initSliderColors();
displayColors();
});
brightNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255
bright.value = checkNumVal(brightNumVal, bright.value);
data.brightness = bright.value;
bright.value = checkNumVal8(brightNumVal, bright.value);
state.brightness = bright.value;
initSliderColors();
// Send Brightness
clearTimeout(sendIt);
@@ -1422,14 +1466,14 @@ function changeRangeNumVal(){
});
speedNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255
speed.value = checkNumVal(speedNumVal, speed.value);
data.speed = speed.value;
speed.value = checkNumVal8(speedNumVal, speed.value);
segstate.speed = speed.value;
// Send Speed
clearTimeout(sendIt);
sendIt = setTimeout(function() { set_speed(); }, 50);
});
}
function checkNumVal(numVal, curVal) {
function checkNumVal8(numVal, curVal) {
if(numVal.value > 255) {
alert(language[settings.lang]["not_greater"]);
numVal.value = curVal;
@@ -1440,6 +1484,17 @@ function checkNumVal(numVal, curVal) {
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
function initcolorSliders(){
var event = new Event('change');
@@ -1447,7 +1502,7 @@ function initcolorSliders(){
displayColors();
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
// Trigger onChange event to send value
redNumVal.dispatchEvent(event);
});
@@ -1456,7 +1511,7 @@ function initcolorSliders(){
displayColors();
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
// Trigger onChange event to send value
greenNumVal.dispatchEvent(event);
});
@@ -1465,7 +1520,7 @@ function initcolorSliders(){
displayColors();
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
// Trigger onChange event to send value
blueNumVal.dispatchEvent(event);
});
@@ -1474,7 +1529,7 @@ function initcolorSliders(){
displayColors();
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
// Trigger onChange event to send value
whiteNumVal.dispatchEvent(event);
});
@@ -1482,14 +1537,14 @@ function initcolorSliders(){
bright.addEventListener('input', () => {
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
// Trigger onChange event to send value
brightNumVal.dispatchEvent(event);
});
speed.addEventListener('input', () => {
changeRangeNumVal();
colorNumrVals();
colorNumVals();
// Trigger onChange event to send value
speedNumVal.dispatchEvent(event);
});
@@ -1518,8 +1573,11 @@ function xhttp(url, post, callback) {
xhr.send(post);
}
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) {
//console.log("Getting modes list via REST:", e);
console.log("Getting modes list via REST:", e);
if (e && e.substring(0,6) !== "ERROR!") {
modes = JSON.parse(e);
if (typeof modes[0] !== "undefined") {
@@ -1538,6 +1596,9 @@ function getModes() {
}
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) {
console.log("Getting config via REST:", e);
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_user !== "undefined") config.mqtt_user = res.mqtt_user;
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_rgbo !== "undefined") {
config.ws_rgbo = res.ws_rgbo;
config.enable_rgbw = config.ws_rgbo.includes("W");
}
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.transEffect !== "undefined") config.transitionEffects = res.transEffect;
if (typeof res.ws_trans !== "undefined") config.ws_trans = res.ws_trans;
}
} else {
console.error(e);
@@ -1567,9 +1628,9 @@ function getConfig() {
} else {
document.getElementById("white").parentNode.className = "hidden";
white.value = 0;
data.color.w = 0;
data.color.w2 = 0;
data.color.w3 = 0;
segstate.color.w = 0;
segstate.color.w2 = 0;
segstate.color.w3 = 0;
}
});
}
@@ -1600,11 +1661,11 @@ function showModes(mode, index) {
document.getElementById("modes").appendChild(div);
}
function readSettings() {
document.getElementById("percentage").innerHTML = "33%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "33,100");
document.getElementById("percentage").innerHTML = "25%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "25,100");
document.getElementById("modal-content").innerHTML = language.en.loadSettings;
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) : {};
// Replace default settings with saved ones
for (var set in settings) {
@@ -1612,8 +1673,12 @@ function readSettings() {
if (typeof(tmpsettings[set]) !== "undefined") settings[set] = tmpsettings[set];
}
applySettings();
if (e && e.substring(0,6) !== "ERROR!") connectAdditionalNodes();
else console.warn("ERROR loading settings", e);
if (e && e.substring(0,6) !== "ERROR!") {
connectAdditionalNodes();
} else {
console.warn("ERROR loading settings", e);
saveSettings();
}
});
}
function applySettings() {
@@ -1678,13 +1743,13 @@ function onSelectColNum(colnum) {
x = document.getElementById("colorSel" + colnum);
x.className = x.className.replace(/\belevation-3\b/g, "elevation-9");
// Set ColorPicker and Sliders to selected color
red.value = data.color["r" + (colnum > 1 ? colnum : "")];
green.value = data.color["g" + (colnum > 1 ? colnum : "")];
blue.value = data.color["b" + (colnum > 1 ? colnum : "")];
white.value = data.color["w" + (colnum > 1 ? colnum : "")];
red.value = segstate.color["r" + (colnum > 1 ? colnum : "")];
green.value = segstate.color["g" + (colnum > 1 ? colnum : "")];
blue.value = segstate.color["b" + (colnum > 1 ? colnum : "")];
white.value = segstate.color["w" + (colnum > 1 ? colnum : "")];
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
}
function initSettings() {
// Add languages to language select
@@ -1736,11 +1801,33 @@ function initSettings() {
config.mqtt_pass = mqtt_pass.value;
ws_send("Cmw" + config.mqtt_pass);
});
var count = document.getElementById("selectcount");
count.value = config.ws_cnt;
count.addEventListener('change', ()=>{
config.ws_cnt = count.value;
ws_send("Csc" + config.ws_cnt);
var selsegment = document.getElementById("selectseg");
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;
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");
pin.value = config.ws_pin;
@@ -1760,6 +1847,28 @@ function initSettings() {
config.ws_rgbo = rgbo.value;
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");
for (var code in selectoptrev) {
var option = document.createElement("OPTION");
@@ -1767,10 +1876,10 @@ function initSettings() {
option.innerHTML = selectoptrev[code];
optrev.appendChild(option);
}
optrev.value = (config.ws_fxopt & 128);
optrev.value = (segstate.ws_fxopt & 128);
optrev.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt);
segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("So" + segstate.ws_fxopt);
});
var optfade = document.getElementById("selectoptfade");
for (var code in selectoptfade) {
@@ -1779,10 +1888,10 @@ function initSettings() {
option.innerHTML = selectoptfade[code];
optfade.appendChild(option);
}
optfade.value = (config.ws_fxopt & 112);
optfade.value = (segstate.ws_fxopt & 112);
optfade.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt);
segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("So" + segstate.ws_fxopt);
});
var optgamma = document.getElementById("selectoptgamma");
for (var code in selectoptgamma) {
@@ -1791,10 +1900,10 @@ function initSettings() {
option.innerHTML = selectoptgamma[code];
optgamma.appendChild(option);
}
optgamma.value = (config.ws_fxopt & 8);
optgamma.value = (segstate.ws_fxopt & 8);
optgamma.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt);
segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("So" + segstate.ws_fxopt);
});
var optsize = document.getElementById("selectoptsize");
for (var code in selectoptsize) {
@@ -1803,10 +1912,10 @@ function initSettings() {
option.innerHTML = selectoptsize[code];
optsize.appendChild(option);
}
optsize.value = (config.ws_fxopt & 6)
optsize.value = (segstate.ws_fxopt & 6)
optsize.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt);
segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("So" + segstate.ws_fxopt);
});
slavenodes.value = settings.slave_nodes;
lang.addEventListener('change', ()=>{
@@ -1820,9 +1929,9 @@ function initSettings() {
redrawColorPicker();
});
var settransitionEffects = document.getElementById("set-transitionEffects");
settransitionEffects.checked = config.transitionEffects;
settransitionEffects.checked = config.ws_trans;
settransitionEffects.addEventListener('change', ()=>{
config.transitionEffects = settransitionEffects.checked;
config.ws_trans = settransitionEffects.checked;
if (settransitionEffects.checked) {
document.getElementById("settransitionEffectsbgcolor").style.backgroundColor = settings.theme_btn;
ws_send("Ce1");
@@ -1855,6 +1964,7 @@ function initSettings() {
settings.theme_back = colback.value;
document.getElementById("container").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("selectoptrev").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++) {
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("redNum").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() {
data.connection = new ReconnectingWebSocket(ws_url, "arduino", ws_options);
document.getElementById("percentage").innerHTML = "67%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "67,100");
document.getElementById("percentage").innerHTML = "75%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "75,100");
document.getElementById("modal-content").innerHTML = language[settings.lang].loadWebsock;
// When the connection is open, send some data to the server
@@ -2031,12 +2142,12 @@ function ws_connect() {
con.className = "hidden";
con = document.getElementById("connected");
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("C"); }, 3000);
//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
@@ -2069,53 +2180,56 @@ function ws_connect() {
// document.getElementById('modal').style.display = "none";
// console.log("res", res);
if (res) {
// Status starts here
if (typeof res.mode !== "undefined") data.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.segment !== "undefined") { state.segment= res.segment; document.getElementById("selectseg").value = state.segment; }
if (typeof res.mode !== "undefined") { state.mode = res.mode; }
if (typeof res.brightness !== "undefined") {
data.brightness = res.brightness;
state.brightness = res.brightness;
// init ColorSliderVals
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") {
data.color.w = res.color[0];
data.color.r = res.color[1];
data.color.g = res.color[2];
data.color.b = res.color[3];
data.color.hex = rgbToHex([res.color[0], res.color[1], res.color[2], res.color[3]]);
data.color.w2 = res.color[4];
data.color.r2 = res.color[5];
data.color.g2 = res.color[6];
data.color.b2 = res.color[7];
data.color.hex2 = rgbToHex([res.color[4], res.color[5], res.color[6], res.color[7]]);
data.color.w3 = res.color[8];
data.color.r3 = res.color[9];
data.color.g3 = res.color[10];
data.color.b3 = res.color[11];
data.color.hex3 = rgbToHex([res.color[8], res.color[9], res.color[10], res.color[11]]);
segstate.color.w = res.color[0];
segstate.color.r = res.color[1];
segstate.color.g = res.color[2];
segstate.color.b = res.color[3];
segstate.color.hex = rgbToHex([res.color[0], res.color[1], res.color[2], res.color[3]]);
segstate.color.w2 = res.color[4];
segstate.color.r2 = res.color[5];
segstate.color.g2 = res.color[6];
segstate.color.b2 = res.color[7];
segstate.color.hex2 = rgbToHex([res.color[4], res.color[5], res.color[6], res.color[7]]);
segstate.color.w3 = res.color[8];
segstate.color.r3 = res.color[9];
segstate.color.g3 = res.color[10];
segstate.color.b3 = res.color[11];
segstate.color.hex3 = rgbToHex([res.color[8], res.color[9], res.color[10], res.color[11]]);
// init ColorSliderVals
if (data.color_num === 1) {
red.value = data.color.r;
green.value = data.color.g;
blue.value = data.color.b;
white.value = data.color.w;
red.value = segstate.color.r;
green.value = segstate.color.g;
blue.value = segstate.color.b;
white.value = segstate.color.w;
}
if (data.color_num === 2) {
red.value = data.color.r2;
green.value = data.color.g2;
blue.value = data.color.b2;
white.value = data.color.w2;
red.value = segstate.color.r2;
green.value = segstate.color.g2;
blue.value = segstate.color.b2;
white.value = segstate.color.w2;
}
if (data.color_num === 3) {
red.value = data.color.r3;
green.value = data.color.g3;
blue.value = data.color.b3;
white.value = data.color.w3;
red.value = segstate.color.r3;
green.value = segstate.color.g3;
blue.value = segstate.color.b3;
white.value = segstate.color.w3;
}
}
// 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_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.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_rgbo !== "undefined") {
config.ws_rgbo = res.ws_rgbo;
@@ -2134,19 +2249,20 @@ function ws_connect() {
} else {
document.getElementById("white").parentNode.className = "hidden";
white.value = 0;
data.color.w = 0;
data.color.w2 = 0;
data.color.w3 = 0;
segstate.color.w = 0;
segstate.color.w2 = 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_trans !== "undefined") { config.ws_trans = res.ws_trans; document.getElementById("set-transitionEffects").value = config.ws_trans; }
if (typeof res.ws_fxopt !== "undefined") {
config.ws_fxopt = res.ws_fxopt;
document.getElementById("selectoptrev").value = (config.ws_fxopt & 128);
document.getElementById("selectoptfade").value = (config.ws_fxopt & 112);
document.getElementById("selectoptgamma").value = (config.ws_fxopt & 8);
document.getElementById("selectoptsize").value = (config.ws_fxopt & 6);
segstate.ws_fxopt = res.ws_fxopt;
document.getElementById("selectoptrev").value = (segstate.ws_fxopt & 128);
document.getElementById("selectoptfade").value = (segstate.ws_fxopt & 112);
document.getElementById("selectoptgamma").value = (segstate.ws_fxopt & 8);
document.getElementById("selectoptsize").value = (segstate.ws_fxopt & 6);
}
// Modes starts here
if (typeof res[0] !== "undefined") {
@@ -2157,18 +2273,22 @@ function ws_connect() {
});
}
// init Color Vals
colorNumrVals();
colorNumVals();
initSliderColors();
// init Change Range Val
changeRangeNumVal();
// init Colors controls
// init display Colors
displayColors(true);
console.log("displayColors finished!");
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
//document.getElementById(data.ws2812fx_mode).style.backgroundColor = settings.theme_btnsel;
//document.getElementById(segstate.mode).style.backgroundColor = settings.theme_btnsel;
// Close Loading Modal
setTimeout(() => {
document.getElementById('modal').style.display = "none";
@@ -2212,38 +2332,45 @@ function select_active_button() {
for (i = 0; i < btns.length; i++) {
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");
var arr = wsmess.className.split(" ");
if (arr.indexOf("hidden") === -1) {
wsmess.className += " hidden";
}
segments = document.getElementById("segments");
segments.className = segments.className.replace(/\b hidden\b/g, "");
}
if (data.mode >= 1) {
document.getElementById(data.ws2812fx_mode).style.backgroundColor = settings.theme_btnsel;
if (data.ws2812fx_mode === 56) { // AUTOPLAY
if (state.mode >= 1) {
document.getElementById(segstate.mode).style.backgroundColor = settings.theme_btnsel;
if (segstate.mode == 56) { // AUTOPLAY
disable_modebuttons(false);
disable_color_selection(true);
disable_bright_selection(false);
disable_speed_selection(true);
} else if (data.ws2812fx_mode === 57) { //CUSTOM_WS
} else if (segstate.mode == 57) { //CUSTOM_WS
wsmess = document.getElementById("message");
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_color_selection(true);
disable_bright_selection(false);
disable_speed_selection(true);
} else if (data.ws2812fx_mode === 58) { //TV
} else if (segstate.mode == 58) { //TV
disable_modebuttons(false);
disable_color_selection(true);
disable_bright_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_color_selection(true);
disable_bright_selection(false);
disable_speed_selection(true);
} else if (data.ws2812fx_mode === 60) { //Fire2012
} else if (segstate.mode == 60) { //Fire2012
disable_modebuttons(false);
disable_color_selection(true);
disable_bright_selection(false);
@@ -2254,7 +2381,7 @@ function select_active_button() {
disable_bright_selection(false);
disable_speed_selection(false);
}
} else if (data.mode === 0) {
} else if (state.mode == 0) {
document.getElementById("off").style.backgroundColor = settings.theme_btnsel;
disable_modebuttons(false);
disable_color_selection(true);
@@ -2282,32 +2409,32 @@ function disable_modebuttons(status) {
function set_mode(mode_id) {
if (Number.isInteger(mode_id)) {
data.mode = 1;
data.ws2812fx_mode = mode_id;
state.mode = 1;
segstate.mode = mode_id;
} else {
// For named modes
if (mode_id == "off") {
data.mode = 0;
state.mode = 0;
}
}
select_active_button();
ws_send("/" + mode_id);
}
function set_speed() {
ws_send("?" + data.speed);
ws_send("?" + segstate.speed);
}
function set_brightness() {
ws_send("%" + data.brightness);
ws_send("%" + state.brightness);
}
function set_color() {
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) {
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) {
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 hex_color = rgbToHex(color);
var colnum = (data.color_num === 1) ? "" : data.color_num;
data.color["hex" + colnum] = hex_color;
data.color["r" + colnum] = color[0];
data.color["g" + colnum] = color[1];
data.color["b" + colnum] = color[2];
data.color["w" + colnum] = 0;
segstate.color["hex" + colnum] = hex_color;
segstate.color["r" + colnum] = color[0];
segstate.color["g" + colnum] = color[1];
segstate.color["b" + colnum] = color[2];
segstate.color["w" + colnum] = 0;
red.value = color[0];
green.value = color[1];
blue.value = color[2];
@@ -2357,7 +2484,7 @@ function onSelectColor(event) {
displayColors();
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
}
}
function redrawColorPicker() {
@@ -2525,13 +2652,11 @@ document.addEventListener("DOMContentLoaded", function(event) {
getModes();
readSettings();
ws_connect();
ws_send("$")
document.getElementById("modal-content").innerHTML = language.en.loadModes;
ws_send("$");
//ws_send("C");
getConfig();
canvas.width = 400;
canvas.height = 400;
redrawColorPicker();
});
</script>
Binary file not shown.
+55 -42
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 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
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_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_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 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_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)
#define GAMMA 2.5 // Gamma correction for GY-33 sensor
#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 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_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;
uint8_t trans_cnt = 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
#endif
uint8_t selected_segment = 0;
uint8_t prevsegment = 0;
#if defined(ENABLE_REMOTE)
uint8_t selected_color = 1;
uint64_t last_remote_cmd;
@@ -92,9 +96,9 @@ uint8_t selected_segment = 0;
// parameters for automatically cycling favorite patterns
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
{0x0000ff00, 0x000000ff, 0x00000000, 200, 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, 40, 45, 15000}, // fireworks blue/red for 15 seconds
{0x0000ff00, 0x000000ff, 0x00000000, 180, 3, 10000}, // wipe green/blue for 10 seconds
{0x000000ff, 0x00ff0000, 0x00000000, 100, 14, 10000}, // dual scan blue on red for 10 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
};
@@ -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
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
enum MODE {OFF, HOLD, SET, INIT_STRIP};
MODE mode = SET; // Standard mode that is active when software starts
MODE prevmode = HOLD; // Do not change
enum MODE {OFF, HOLD, SET};
MODE prevmode = HOLD; // Do not change
uint8_t autoCount = 0; // Global variable for storing the counter for automated playback
long autoDelay = 0; // Global variable for storing the time to next auto effect
uint8_t ws2812fx_speed = 196; // Global variable for storing the speed for effects --> smaller == slower
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_trans = 0; // Global variable for storing the brightness before change
uint8_t ws2812fx_mode = 0; // Global variable for storing the WS2812FX mode to set
struct {
uint8_t segment = 0; // Actual selected segment
MODE mode = SET; // Standard mode that is active when software starts
uint8_t brightness = 196; // Global variable for storing the brightness (255 == 100%)
} State;
uint32_t hex_colors[3] = {}; // Color array for setting colors of WS2812FX
uint32_t hex_colors_trans[3] = {}; // Color array of colors of WS2812FX before fading
struct {
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
{
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
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
@@ -196,22 +228,3 @@ bool updateState = false;
byte KeyPressCount_gy33 = 0;
byte prevKeyState_gy33 = HIGH; // button is active low
#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>
#define edit_htm_gz_len 5489
#define edit_htm_gz_len 5563
static const char edit_htm_gz[] PROGMEM ={
0x1f, 0x8b, 0x08, 0x08, 0x10, 0x9c, 0x83, 0x5c, 0x04, 0x00, 0x65, 0x64,
0x69, 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x00, 0xed, 0x1c, 0x67, 0x7b, 0xf2,
0x36, 0xf0, 0x7b, 0x7f, 0x85, 0xeb, 0x8e, 0x40, 0x99, 0x21, 0x24, 0x6f,
0x66, 0x5b, 0x76, 0x12, 0xa0, 0x84, 0x91, 0x84, 0xa4, 0xeb, 0x31, 0xb6,
0x00, 0x27, 0xc6, 0x76, 0x6c, 0x13, 0x20, 0x69, 0xfa, 0xdb, 0x7b, 0x92,
0xbc, 0x07, 0x38, 0xa3, 0xf3, 0x29, 0xef, 0x00, 0x4b, 0x77, 0xa7, 0xbb,
0xd3, 0xe9, 0x74, 0x3a, 0x49, 0x3e, 0xfe, 0xbc, 0xda, 0xa9, 0x0c, 0x6e,
0x2e, 0x6a, 0xcc, 0xd4, 0x98, 0x49, 0xdf, 0x7e, 0x76, 0x8c, 0xbf, 0x18,
0x89, 0x93, 0x27, 0x27, 0x2c, 0x92, 0xd9, 0x6f, 0x3f, 0x63, 0x98, 0xe3,
0x29, 0xe2, 0x04, 0xfc, 0x03, 0x7e, 0x1a, 0xa2, 0x21, 0xa1, 0x6f, 0xfb,
0x17, 0x67, 0xf5, 0x7a, 0x9f, 0xa9, 0x09, 0xa2, 0xa1, 0x68, 0xc7, 0x39,
0x52, 0x68, 0x02, 0xe8, 0xc6, 0x4a, 0x42, 0x8c, 0xb1, 0x52, 0xd1, 0x09,
0x6b, 0xa0, 0xa5, 0x91, 0xe3, 0x75, 0x9d, 0x65, 0x66, 0x48, 0x10, 0xb9,
0x13, 0x56, 0xe7, 0x35, 0x44, 0x89, 0x92, 0x4f, 0x96, 0x57, 0x64, 0x0c,
0xd3, 0x46, 0xf2, 0x9c, 0x79, 0x86, 0x42, 0xfa, 0x79, 0xca, 0x88, 0xb2,
0x80, 0x96, 0x87, 0xcc, 0x4e, 0x3e, 0x7f, 0x64, 0x97, 0xaa, 0x8a, 0x2e,
0x1a, 0xa2, 0x22, 0x1f, 0x32, 0xdc, 0x48, 0x57, 0xa4, 0xb9, 0x81, 0x9c,
0x3a, 0x09, 0x8d, 0x8d, 0x43, 0x66, 0x57, 0x5d, 0x3a, 0x45, 0x23, 0x45,
0x13, 0x90, 0x76, 0xc8, 0x6c, 0xab, 0x4b, 0x06, 0xc0, 0x45, 0x81, 0xf9,
0xa2, 0x58, 0x2c, 0xba, 0xea, 0x39, 0xfe, 0x7e, 0xa2, 0x29, 0x73, 0x59,
0xc8, 0xf0, 0x8a, 0xa4, 0x00, 0xe4, 0x17, 0xf5, 0x5d, 0xfc, 0xc7, 0x01,
0x11, 0x44, 0x5d, 0x95, 0xb8, 0xd5, 0x21, 0x23, 0x2b, 0x32, 0x72, 0x53,
0x5e, 0x66, 0xf4, 0x29, 0x27, 0x28, 0x8b, 0x43, 0x26, 0x0f, 0x7f, 0xb6,
0xf3, 0xd0, 0x84, 0x36, 0x19, 0x71, 0x09, 0x26, 0x9f, 0x36, 0xff, 0x66,
0x8b, 0x4c, 0xd2, 0xc1, 0x18, 0x83, 0x98, 0x19, 0x5d, 0x7c, 0x42, 0xc0,
0x4e, 0xc1, 0x64, 0xd2, 0xa9, 0x18, 0x73, 0x33, 0x51, 0x82, 0x56, 0x74,
0x4e, 0xd6, 0x33, 0x3a, 0xd2, 0xc4, 0xb1, 0x0f, 0x60, 0x81, 0xc4, 0xc9,
0xd4, 0x38, 0x1c, 0x29, 0x92, 0x60, 0xd5, 0xbc, 0x84, 0x69, 0x70, 0x2e,
0xb9, 0x94, 0x28, 0x89, 0x3a, 0xb4, 0x89, 0x3b, 0xc3, 0xcf, 0xbf, 0xa1,
0xa8, 0xc0, 0xb8, 0x57, 0x79, 0x9e, 0x82, 0x19, 0xa7, 0x4d, 0x44, 0xd9,
0x53, 0xa4, 0x72, 0x82, 0x20, 0xca, 0x13, 0x28, 0x5b, 0xc7, 0x01, 0x34,
0x0a, 0x1c, 0x04, 0x3b, 0x4c, 0x43, 0x12, 0x67, 0x88, 0x8f, 0xc8, 0xd5,
0x84, 0x28, 0x67, 0x16, 0xa2, 0x60, 0x4c, 0x0f, 0x99, 0xbd, 0xbc, 0x5b,
0x23, 0xfc, 0x5c, 0xd3, 0xa1, 0x33, 0x00, 0x59, 0x04, 0xb2, 0xda, 0xda,
0xd6, 0x74, 0x95, 0x93, 0x5d, 0xed, 0xd1, 0x6e, 0xa4, 0xdd, 0x1c, 0xec,
0x43, 0x51, 0x96, 0x44, 0x19, 0x65, 0x46, 0x92, 0xc2, 0xdf, 0x87, 0xc8,
0xb5, 0xa7, 0x2e, 0x37, 0x48, 0x76, 0x38, 0x55, 0x1e, 0x91, 0xc6, 0x3c,
0xbb, 0x2c, 0xc7, 0x6c, 0x6c, 0x3d, 0x86, 0xc9, 0xa6, 0xcd, 0x5e, 0xad,
0x56, 0xb3, 0x30, 0x6c, 0x34, 0x5d, 0xcf, 0x18, 0x30, 0x32, 0x1e, 0x45,
0xb4, 0x80, 0x5e, 0x4c, 0xfb, 0x4a, 0x1c, 0xad, 0x3a, 0x1c, 0x47, 0x74,
0xd8, 0xc6, 0xee, 0x7f, 0xf9, 0x2c, 0xb4, 0x51, 0x51, 0x56, 0xe7, 0x06,
0xf3, 0x1c, 0x6b, 0xb0, 0x29, 0x2a, 0xc7, 0x8b, 0xc6, 0x0a, 0x9a, 0xdb,
0x40, 0xf4, 0xd9, 0x63, 0xc6, 0x98, 0x0f, 0x6d, 0xc6, 0x49, 0xcc, 0x36,
0x1e, 0x92, 0x57, 0x48, 0x13, 0x38, 0x99, 0x4b, 0x33, 0x25, 0x4d, 0xe4,
0x40, 0xe2, 0x7e, 0x88, 0xf1, 0x67, 0x66, 0xca, 0x53, 0x66, 0x0e, 0x85,
0x50, 0x21, 0x21, 0xde, 0xf0, 0x1b, 0x32, 0x0c, 0x8c, 0xd1, 0xbd, 0x68,
0xac, 0x03, 0x71, 0x55, 0xc5, 0xd2, 0x43, 0x84, 0x49, 0xe5, 0xf3, 0xe3,
0x18, 0x26, 0x1a, 0x49, 0xd1, 0x34, 0x04, 0x87, 0x2e, 0x36, 0x92, 0x8c,
0x80, 0x78, 0x45, 0xe3, 0xa8, 0x96, 0xc1, 0x98, 0x90, 0x26, 0x89, 0x1b,
0xf9, 0xa3, 0xfd, 0x94, 0x02, 0xff, 0x3c, 0x42, 0x12, 0x7c, 0xe3, 0x21,
0x1f, 0x34, 0x03, 0xf2, 0xa7, 0x00, 0x9e, 0x26, 0x16, 0xb5, 0xdf, 0x09,
0x15, 0xff, 0x88, 0x89, 0xa5, 0x2e, 0xc2, 0x46, 0x3a, 0xac, 0xf0, 0xf0,
0x70, 0x84, 0xc6, 0x8a, 0x86, 0x98, 0xe7, 0x37, 0xea, 0x8d, 0xf0, 0x76,
0x08, 0xcc, 0x70, 0x23, 0x09, 0x09, 0xb6, 0xc8, 0x41, 0x72, 0x02, 0x1a,
0x73, 0x73, 0xc9, 0x08, 0xb1, 0xcf, 0xec, 0x5e, 0xac, 0x36, 0xf8, 0x29,
0xe2, 0xef, 0x91, 0x70, 0x28, 0x2b, 0x46, 0xc2, 0x6e, 0x30, 0x19, 0xa9,
0x16, 0xe2, 0x41, 0x3e, 0x52, 0x2f, 0x6e, 0x7f, 0x32, 0xd7, 0xa4, 0x04,
0x2b, 0x70, 0x06, 0x77, 0x28, 0xce, 0xb8, 0x09, 0xca, 0xa9, 0xf2, 0xe4,
0x68, 0xc4, 0xe9, 0x68, 0xaf, 0x98, 0x16, 0xaf, 0xca, 0x9d, 0xde, 0x22,
0xdf, 0x6c, 0x4c, 0x94, 0x12, 0x7c, 0x7e, 0xe8, 0x5f, 0x4e, 0x6b, 0x97,
0x13, 0xf8, 0x55, 0xc6, 0x8f, 0x95, 0x49, 0xa5, 0x74, 0x83, 0x7f, 0xd4,
0x3b, 0x68, 0x71, 0x89, 0x7f, 0x34, 0x86, 0xbd, 0xfa, 0xf5, 0x69, 0x6f,
0x30, 0x2a, 0xdc, 0xe6, 0x85, 0x42, 0x7d, 0x75, 0xdb, 0x2d, 0x97, 0x6f,
0x1b, 0x07, 0xe2, 0x6d, 0xbf, 0x7c, 0x3e, 0xba, 0xae, 0xcb, 0xb7, 0x57,
0xe7, 0xd2, 0xcd, 0x75, 0x6f, 0x97, 0xe7, 0x25, 0xe9, 0x02, 0x23, 0xa8,
0xcb, 0xf3, 0x5e, 0xad, 0x7e, 0x89, 0x7e, 0xd0, 0x74, 0xa9, 0xbd, 0x3d,
0xcf, 0xe7, 0x4b, 0xdd, 0x49, 0x03, 0x5c, 0xf4, 0x8a, 0x93, 0xea, 0xf5,
0x4e, 0x33, 0x55, 0x91, 0xce, 0xce, 0x9a, 0xdd, 0xe6, 0xea, 0xe1, 0xf2,
0xaa, 0xfb, 0x38, 0xa8, 0xd5, 0x76, 0xaa, 0xb3, 0xd2, 0xb4, 0xb5, 0x28,
0x4d, 0x2f, 0xf7, 0xbb, 0xb7, 0xca, 0x69, 0xb1, 0x54, 0xe8, 0x16, 0x26,
0xed, 0x7e, 0x9d, 0xe3, 0x51, 0xb1, 0x5d, 0x31, 0xce, 0xf7, 0xfb, 0x17,
0xe5, 0xfa, 0xa2, 0x74, 0xdf, 0x9b, 0x8b, 0xa7, 0x4d, 0xb5, 0xb4, 0xa7,
0xf7, 0x7e, 0xc8, 0xb5, 0xe6, 0x9f, 0x9e, 0x1a, 0xbb, 0xe2, 0x76, 0xf1,
0x9e, 0x37, 0xb8, 0xcb, 0x87, 0x5e, 0x63, 0xda, 0x18, 0xca, 0xf3, 0x83,
0x4e, 0xee, 0xc2, 0xf8, 0xd4, 0x7e, 0xd2, 0xdb, 0xe2, 0xbd, 0xf4, 0x58,
0x4f, 0x1d, 0x18, 0x85, 0xfb, 0xeb, 0x41, 0xf5, 0x71, 0x75, 0xa6, 0x95,
0xf4, 0x52, 0x9e, 0x6b, 0xf6, 0x7a, 0xe2, 0xf6, 0x20, 0x5f, 0xc9, 0x4d,
0xcf, 0x8b, 0xad, 0xcb, 0x91, 0xb1, 0x9b, 0xdb, 0xd7, 0x7e, 0x50, 0xaf,
0xaf, 0x24, 0x75, 0xbf, 0xd7, 0xd7, 0x0e, 0xce, 0x8b, 0xf9, 0x51, 0x71,
0x7f, 0xbc, 0xac, 0x73, 0x83, 0xee, 0x41, 0x6a, 0x6c, 0xec, 0xd7, 0x6e,
0xf7, 0xda, 0xe7, 0x37, 0xa3, 0x7c, 0xe7, 0x3e, 0x25, 0xc8, 0x37, 0x0d,
0x75, 0x76, 0x31, 0x19, 0x2e, 0x9a, 0x67, 0xa5, 0xc7, 0xd6, 0x72, 0xff,
0xf1, 0x66, 0xc8, 0xef, 0x36, 0x84, 0x76, 0xa9, 0x7b, 0x3e, 0xe9, 0xd6,
0xee, 0xd5, 0xbb, 0xde, 0x60, 0xba, 0xb3, 0x37, 0xe8, 0x17, 0x2e, 0x53,
0xd5, 0xeb, 0xeb, 0x5c, 0x75, 0xfb, 0xd3, 0xf5, 0xfc, 0x66, 0x32, 0xdb,
0x57, 0x17, 0xe7, 0xab, 0x9b, 0x6d, 0x59, 0xbd, 0xd5, 0x6f, 0x9b, 0x9d,
0xe5, 0xd9, 0xac, 0x73, 0xb5, 0x7d, 0x96, 0x9b, 0x16, 0x53, 0x9d, 0xbd,
0xc7, 0xda, 0x64, 0xb7, 0x51, 0xb9, 0x2d, 0xab, 0x93, 0x59, 0x69, 0x6f,
0x3a, 0xdc, 0x5f, 0x9c, 0x36, 0x2f, 0x4f, 0xab, 0xbd, 0xf2, 0xb0, 0x7b,
0x23, 0xf2, 0xdd, 0xa2, 0x26, 0xf1, 0x3b, 0x83, 0x71, 0xfe, 0xaa, 0xad,
0xef, 0x57, 0x4f, 0xcb, 0xfd, 0xfd, 0xbd, 0x62, 0xbd, 0x70, 0x53, 0xd7,
0xd5, 0xbb, 0xc9, 0xe5, 0xcd, 0x5d, 0x73, 0x98, 0x2b, 0x3d, 0xed, 0x4c,
0x74, 0xa1, 0x2b, 0x14, 0x10, 0x2a, 0x9f, 0x2e, 0x66, 0x42, 0xe3, 0x7a,
0x78, 0xca, 0x4f, 0xca, 0x8d, 0xfe, 0xfd, 0xed, 0xb0, 0x33, 0x54, 0xa6,
0x7c, 0x6d, 0x88, 0x46, 0x3d, 0xa5, 0xcb, 0x97, 0x26, 0x77, 0x0f, 0x10,
0x36, 0xfd, 0x70, 0x93, 0x2a, 0x5d, 0xad, 0xe6, 0x3b, 0xb7, 0x3b, 0x7a,
0xa9, 0xf9, 0x30, 0x6e, 0x2a, 0x8d, 0xb6, 0x8e, 0x16, 0x65, 0x54, 0x3b,
0xeb, 0x5c, 0x4c, 0xba, 0xcb, 0xe5, 0xc5, 0xf9, 0xd9, 0x1d, 0xdf, 0x38,
0xdd, 0x7b, 0x30, 0x5a, 0xb9, 0x7c, 0x49, 0x28, 0x55, 0x9f, 0x9a, 0x0d,
0x79, 0x3e, 0xaf, 0xa6, 0x0a, 0x46, 0xab, 0xf9, 0xa9, 0xbb, 0x5f, 0x9d,
0x9e, 0x9e, 0x8e, 0x3a, 0xe5, 0xeb, 0x54, 0xb3, 0xf6, 0xc4, 0x9f, 0xb6,
0xe6, 0x37, 0xfc, 0x7e, 0xa1, 0x7d, 0x5f, 0xbb, 0x44, 0xf7, 0x2d, 0x71,
0x31, 0x7f, 0xbc, 0x3a, 0x4d, 0x4d, 0xe6, 0xdd, 0x72, 0xf7, 0xa9, 0xd3,
0x28, 0x0e, 0x85, 0xd2, 0x68, 0xbf, 0xd6, 0xe1, 0x7b, 0xfc, 0x43, 0xf7,
0xb1, 0x7a, 0x7f, 0x53, 0x10, 0x2b, 0xad, 0xf9, 0xb2, 0x56, 0x39, 0x2f,
0xee, 0x9c, 0x2b, 0xa3, 0xf6, 0x50, 0x99, 0x1b, 0x0f, 0x8d, 0x49, 0x95,
0x2b, 0x0c, 0x3e, 0x5d, 0x3e, 0xb4, 0x9a, 0x0b, 0xe3, 0xa0, 0xd9, 0x5b,
0xcd, 0x97, 0xcd, 0xab, 0xf2, 0xea, 0xe1, 0x6a, 0x38, 0x7c, 0x38, 0x53,
0x2a, 0x95, 0xcb, 0x4a, 0xe9, 0x61, 0x7a, 0xd9, 0x11, 0x95, 0xc1, 0x75,
0xe5, 0x53, 0xa3, 0x38, 0xe8, 0xd6, 0x3a, 0xd5, 0x7c, 0xe9, 0x62, 0x55,
0xc8, 0x7d, 0x6a, 0x14, 0x86, 0xea, 0x7c, 0xfb, 0xbc, 0x98, 0x92, 0x96,
0xa8, 0x5b, 0x1c, 0x0c, 0xcb, 0xa3, 0xb3, 0x41, 0x55, 0x55, 0xae, 0x90,
0x04, 0x96, 0x51, 0xbe, 0xaa, 0x8f, 0x16, 0xf3, 0x5d, 0xa5, 0xdd, 0x3e,
0xbf, 0x2c, 0x4f, 0x95, 0xe1, 0x6a, 0xd7, 0x98, 0x09, 0x3d, 0xbe, 0xbd,
0x58, 0xcd, 0x2e, 0x0a, 0x9d, 0x56, 0x97, 0x6b, 0xdd, 0x2d, 0x0f, 0x72,
0x8f, 0x72, 0x59, 0xd9, 0xbb, 0xda, 0x69, 0xee, 0x89, 0x4f, 0xa5, 0xc1,
0xac, 0x2f, 0xb7, 0xb9, 0x7c, 0xf5, 0xe1, 0xd3, 0x18, 0x69, 0x67, 0xca,
0xf4, 0x7c, 0xaa, 0x6d, 0xab, 0xf9, 0xed, 0x27, 0x4d, 0x7a, 0x2a, 0x1e,
0x68, 0xb7, 0xf5, 0x62, 0x07, 0xba, 0xe0, 0xfc, 0x7e, 0x58, 0xd8, 0x79,
0xbc, 0xea, 0x3e, 0xdd, 0xa8, 0xa9, 0xc5, 0xe8, 0xa6, 0x71, 0x95, 0x6b,
0xaa, 0xc3, 0xe6, 0xdd, 0x23, 0x0c, 0xe6, 0x7d, 0x43, 0x3f, 0x6b, 0x56,
0xb4, 0xf6, 0x0f, 0xa5, 0x9b, 0xfa, 0xf2, 0xae, 0xd0, 0x68, 0xf6, 0x77,
0x6f, 0xaf, 0x97, 0x93, 0x22, 0x5a, 0x34, 0xf5, 0xf3, 0x31, 0xd7, 0x68,
0x9f, 0xdd, 0xec, 0x36, 0x87, 0x0f, 0x17, 0x4f, 0xfb, 0xad, 0x72, 0xf9,
0x6e, 0x2f, 0xb5, 0xaa, 0x3e, 0x5e, 0x5d, 0x7c, 0x3a, 0x80, 0x6f, 0x35,
0x77, 0x50, 0x3f, 0x50, 0xce, 0x96, 0x3b, 0x1d, 0x51, 0x3f, 0xbd, 0x5e,
0xa0, 0x4f, 0x1d, 0x4e, 0xca, 0x9f, 0x2e, 0x2b, 0x30, 0x88, 0xba, 0x30,
0x22, 0x6b, 0x67, 0x5d, 0x18, 0x90, 0xb5, 0x33, 0x18, 0x9a, 0xa4, 0x68,
0x0a, 0xff, 0x9d, 0xe1, 0x0a, 0x5a, 0x54, 0x83, 0xc7, 0x29, 0x85, 0x5d,
0x54, 0xf7, 0x6b, 0xb9, 0xf2, 0xed, 0xa4, 0x74, 0x91, 0x7f, 0x98, 0x36,
0xef, 0x76, 0xb4, 0x61, 0xe7, 0x53, 0x09, 0x7f, 0x6a, 0x52, 0x7d, 0x70,
0xdf, 0x9f, 0x77, 0x67, 0x95, 0x0a, 0x9b, 0x04, 0x4f, 0x9c, 0xd1, 0x90,
0x8a, 0x38, 0xe3, 0x2d, 0x6e, 0x07, 0x4f, 0x40, 0x71, 0x5d, 0xd1, 0x86,
0x68, 0x69, 0x4a, 0x03, 0x51, 0x66, 0x7b, 0xcf, 0x1d, 0xb2, 0x11, 0xc8,
0xf0, 0x2a, 0x98, 0xf5, 0x0c, 0x91, 0xe7, 0xa4, 0x0c, 0x27, 0x89, 0x13,
0x98, 0x99, 0x66, 0xa2, 0x20, 0x48, 0xb1, 0x26, 0x95, 0x50, 0xff, 0x98,
0x71, 0xc2, 0x92, 0xed, 0x7d, 0x75, 0xb9, 0x31, 0x00, 0x89, 0x12, 0x93,
0x84, 0x69, 0x38, 0x22, 0x61, 0x59, 0x87, 0x57, 0x12, 0x8e, 0x9a, 0x02,
0xf8, 0xa7, 0x54, 0x73, 0x3a, 0xc5, 0xf3, 0x6a, 0x5c, 0xe1, 0xc2, 0xf8,
0x26, 0x84, 0x32, 0x3b, 0x31, 0x27, 0x66, 0x6b, 0x62, 0x62, 0x52, 0x31,
0xa6, 0x0e, 0x6f, 0x13, 0x20, 0x44, 0xb0, 0x89, 0xdc, 0x37, 0x0c, 0x0d,
0x98, 0x18, 0x4e, 0xb8, 0xe3, 0x78, 0x50, 0x00, 0x03, 0x81, 0xd1, 0x0c,
0x7f, 0xd3, 0x08, 0x49, 0xd1, 0x98, 0xd1, 0x7c, 0x32, 0x16, 0x97, 0xcc,
0x37, 0x39, 0x13, 0xe7, 0x7b, 0xb2, 0x70, 0x63, 0xe8, 0xba, 0x8d, 0xe1,
0x64, 0x81, 0x49, 0x58, 0x51, 0x17, 0x0e, 0xe1, 0x05, 0x60, 0x97, 0x47,
0x19, 0x55, 0x5c, 0x22, 0x29, 0x43, 0x62, 0x99, 0xc3, 0x7c, 0x92, 0xa2,
0x52, 0x2e, 0x83, 0xb2, 0x39, 0xc5, 0x4e, 0x00, 0xc7, 0xc9, 0x30, 0xdb,
0x51, 0xe6, 0xcd, 0x12, 0x8b, 0xc3, 0x8c, 0xc9, 0x61, 0xc6, 0xe2, 0x30,
0x63, 0x72, 0x28, 0xca, 0x63, 0x51, 0x16, 0x0d, 0xc4, 0x6c, 0xeb, 0x44,
0x50, 0x47, 0x54, 0x93, 0x71, 0x8b, 0xf6, 0x3d, 0x5a, 0x8d, 0x35, 0x6e,
0x86, 0xf4, 0xd8, 0xa4, 0x6d, 0x1a, 0x6e, 0x56, 0xc7, 0x9a, 0x32, 0x83,
0x12, 0xa7, 0x32, 0x18, 0x8b, 0xdb, 0x5c, 0xb8, 0x81, 0x0c, 0x25, 0x2e,
0x96, 0x23, 0x85, 0xbf, 0xe3, 0xbe, 0x98, 0xab, 0x92, 0xc2, 0x09, 0x64,
0xf1, 0x11, 0x2b, 0x42, 0xf7, 0xaf, 0xf0, 0x34, 0x3a, 0x36, 0x83, 0x6b,
0xbe, 0xc0, 0xd0, 0x2e, 0xec, 0x47, 0x8e, 0xec, 0x42, 0xd1, 0xae, 0x72,
0x84, 0xc8, 0x10, 0x42, 0x64, 0x09, 0x1c, 0x6a, 0xf8, 0xa1, 0x6b, 0x32,
0x5a, 0x88, 0x17, 0x42, 0xfe, 0x25, 0xd7, 0x17, 0xd8, 0x4a, 0x5e, 0x25,
0xa5, 0x97, 0xe1, 0x91, 0x62, 0x18, 0xca, 0x2c, 0x5a, 0x52, 0x67, 0x9c,
0x17, 0xf2, 0x84, 0xe5, 0x40, 0x9f, 0x38, 0xe4, 0x1c, 0xa6, 0x10, 0x49,
0x73, 0xa4, 0x99, 0x2f, 0x54, 0x8d, 0x98, 0xf0, 0x3b, 0x18, 0xb4, 0x7a,
0x22, 0x06, 0xcb, 0x0e, 0x87, 0x0e, 0x2f, 0x2e, 0x16, 0xd6, 0x68, 0x1b,
0x6b, 0x36, 0x28, 0xda, 0xae, 0x9f, 0xda, 0x71, 0x0e, 0xd6, 0x87, 0x4e,
0xde, 0x86, 0xd7, 0x44, 0xd5, 0xb0, 0x32, 0x33, 0xe3, 0xb9, 0xcc, 0x63,
0xb1, 0x18, 0x18, 0xf8, 0x9c, 0x81, 0xea, 0xa2, 0x84, 0x2e, 0x4d, 0x23,
0x4c, 0x98, 0xe3, 0x26, 0xcd, 0xe0, 0xce, 0x4a, 0x33, 0x54, 0x3b, 0x49,
0x87, 0xa1, 0x47, 0x4e, 0x63, 0x96, 0x33, 0xe9, 0xd4, 0x30, 0xd4, 0x23,
0x77, 0xa1, 0xb9, 0xdc, 0x38, 0x61, 0x04, 0x85, 0x9f, 0x63, 0x0a, 0x59,
0x4a, 0xbc, 0x46, 0xe9, 0x25, 0x58, 0x52, 0xcf, 0x3a, 0x79, 0x13, 0x8a,
0x90, 0xc5, 0xb9, 0x24, 0xc0, 0x62, 0xc7, 0xc0, 0x04, 0xeb, 0xaf, 0x9c,
0x41, 0xe8, 0x2f, 0xaa, 0x12, 0x06, 0x18, 0x73, 0x92, 0x8e, 0xfc, 0xf5,
0x32, 0x37, 0xc3, 0x75, 0x24, 0xa6, 0x76, 0x90, 0x1d, 0x16, 0x26, 0xc8,
0x30, 0xdb, 0x2f, 0xaf, 0xce, 0x04, 0x4b, 0xb6, 0x64, 0x96, 0x53, 0x55,
0x24, 0x0b, 0x95, 0xa9, 0x28, 0x09, 0x09, 0x42, 0x29, 0xe9, 0x95, 0x45,
0xe5, 0x8c, 0xe9, 0x6b, 0x44, 0xc1, 0xf0, 0x59, 0x51, 0xc0, 0xac, 0xd0,
0xd1, 0x9c, 0xc1, 0x25, 0xac, 0x17, 0xc0, 0x16, 0x15, 0xaf, 0x0f, 0x7d,
0x75, 0xb6, 0x24, 0x61, 0x78, 0xe6, 0x1a, 0xe8, 0x8a, 0x93, 0xe6, 0x04,
0x26, 0xf7, 0x56, 0x51, 0x31, 0x35, 0x9f, 0xa4, 0xa3, 0x39, 0x18, 0xa8,
0xbc, 0x46, 0x56, 0x0a, 0xe0, 0x16, 0x96, 0x96, 0x64, 0x45, 0x59, 0x46,
0xda, 0xe9, 0xa0, 0xdd, 0x02, 0xe4, 0x2d, 0x6a, 0x3e, 0x5b, 0x6f, 0xe4,
0x8b, 0x52, 0xf4, 0x71, 0x36, 0xbb, 0x17, 0x44, 0xed, 0x55, 0x8c, 0x11,
0x0c, 0x2f, 0x5f, 0xed, 0xfb, 0xaa, 0xa8, 0xbd, 0x95, 0x2d, 0x42, 0x2f,
0xc0, 0x15, 0x36, 0xd4, 0x57, 0xb2, 0x85, 0x51, 0xfc, 0x7c, 0xe1, 0x41,
0xf7, 0x76, 0xc6, 0x30, 0x45, 0xd2, 0x04, 0xfc, 0xf5, 0x8d, 0xe9, 0x29,
0x8c, 0xcc, 0x0b, 0x45, 0x37, 0x2e, 0x34, 0x85, 0x47, 0xba, 0xde, 0x43,
0x0f, 0x73, 0xa4, 0x1b, 0x09, 0x32, 0x84, 0xed, 0xd1, 0x33, 0x66, 0x12,
0xe6, 0x20, 0xce, 0x02, 0xfb, 0xc2, 0xaa, 0x6f, 0x70, 0x06, 0x48, 0x75,
0xc2, 0x14, 0x4d, 0x38, 0x07, 0xd2, 0x06, 0xd4, 0x01, 0x66, 0xae, 0x33,
0x9f, 0x9f, 0x60, 0xe7, 0x95, 0x64, 0x38, 0x09, 0x69, 0x20, 0x6f, 0xad,
0xd7, 0xeb, 0xf4, 0x7e, 0x64, 0x53, 0x5e, 0xa8, 0x14, 0xfb, 0x33, 0xc4,
0x5f, 0x29, 0xa7, 0x0d, 0x5d, 0x55, 0x64, 0x1d, 0x0d, 0xd0, 0x92, 0x0e,
0x35, 0xe7, 0x83, 0x24, 0xdd, 0x8c, 0x79, 0x9c, 0x0f, 0xf1, 0x3d, 0x80,
0x34, 0x06, 0xbc, 0xe9, 0x05, 0x18, 0x6d, 0x82, 0x8c, 0x83, 0x47, 0x3c,
0x00, 0x7c, 0xe8, 0x2f, 0xeb, 0x26, 0xd9, 0xa0, 0xab, 0xa3, 0xc4, 0x3c,
0x32, 0x9a, 0x3c, 0x42, 0xaf, 0xc8, 0xe0, 0x79, 0x87, 0xed, 0x16, 0x7e,
0xb2, 0xb5, 0x76, 0x14, 0x84, 0xcc, 0x2a, 0x32, 0xd1, 0x19, 0x96, 0x14,
0xf1, 0x53, 0xc8, 0xa5, 0x83, 0xe6, 0x22, 0xd4, 0x4e, 0xd1, 0x1d, 0xf3,
0x81, 0x08, 0x6f, 0x56, 0x05, 0x67, 0x65, 0xb6, 0x56, 0x37, 0x1f, 0x3d,
0xed, 0xd8, 0x40, 0x66, 0x9f, 0x27, 0xa8, 0x53, 0x48, 0x33, 0x6a, 0x38,
0x37, 0x00, 0x93, 0x60, 0x2f, 0x2e, 0x07, 0x00, 0xc1, 0xe6, 0xb0, 0xbf,
0x66, 0x43, 0xe1, 0x74, 0x4c, 0xca, 0x22, 0x0d, 0x10, 0x41, 0x5d, 0xf9,
0x2c, 0x16, 0xe4, 0xe4, 0x25, 0x91, 0xbf, 0x67, 0x4e, 0x6c, 0x2d, 0x26,
0x90, 0xcf, 0x8c, 0x5c, 0x1d, 0x93, 0x25, 0x69, 0xfd, 0xce, 0x38, 0xc1,
0x66, 0xd9, 0x24, 0x98, 0xd2, 0x09, 0x04, 0xaa, 0x49, 0x48, 0x0e, 0x1b,
0x73, 0x4d, 0x76, 0xf1, 0x63, 0x76, 0xc4, 0x9a, 0x5e, 0x35, 0xe7, 0x9c,
0x2c, 0xf6, 0x28, 0x97, 0x9a, 0x14, 0x0e, 0xf5, 0xe2, 0x1b, 0xf6, 0xaf,
0x65, 0x56, 0x42, 0xf2, 0x04, 0x7c, 0xfc, 0x31, 0x53, 0xb0, 0x78, 0xf4,
0x77, 0x15, 0xf5, 0x3e, 0x0e, 0x8a, 0x97, 0x14, 0xd4, 0x7a, 0x05, 0xfe,
0x9c, 0x08, 0x4c, 0x5a, 0x0c, 0x00, 0x4a, 0x9c, 0x6e, 0x9c, 0x59, 0xc0,
0x39, 0x53, 0x3b, 0xf9, 0xb0, 0x86, 0x19, 0xb3, 0x59, 0x8c, 0xa5, 0xcf,
0x47, 0xba, 0xa1, 0xc1, 0xe4, 0x9e, 0x80, 0x2d, 0x87, 0x30, 0x32, 0x1e,
0xa5, 0xbd, 0x84, 0xab, 0xd8, 0xeb, 0xc1, 0x5e, 0xfc, 0x5e, 0x3c, 0x96,
0xda, 0xe8, 0x5c, 0x8b, 0x4d, 0x42, 0x37, 0xf5, 0x46, 0x05, 0xf0, 0x09,
0x1b, 0x94, 0xe6, 0xe5, 0xdf, 0x35, 0xcc, 0x48, 0x14, 0x91, 0x66, 0x5c,
0xe2, 0xfe, 0x98, 0xff, 0x39, 0xed, 0x32, 0x81, 0x75, 0xe3, 0xaf, 0xd3,
0x7f, 0xff, 0x00, 0x24, 0x2d, 0x83, 0xdc, 0x54, 0xda, 0xb7, 0xf5, 0x49,
0x84, 0x35, 0x63, 0x48, 0x1a, 0x63, 0xf8, 0xe4, 0x23, 0x91, 0x87, 0x1f,
0x1a, 0xdc, 0x34, 0x00, 0xe6, 0x12, 0xdf, 0x1d, 0xfe, 0x94, 0x4d, 0xfc,
0xf8, 0x4b, 0xf6, 0xe7, 0x54, 0x32, 0xf9, 0xdd, 0x97, 0xb9, 0x2c, 0x5a,
0x22, 0x3e, 0x61, 0x91, 0x4a, 0xfe, 0xb8, 0xfd, 0xb3, 0x1f, 0x11, 0x97,
0x13, 0xcc, 0xec, 0x37, 0xc9, 0x9f, 0xb2, 0x04, 0x33, 0x12, 0xcd, 0x11,
0x06, 0x07, 0x46, 0xca, 0x98, 0x20, 0xe3, 0x71, 0x44, 0xf2, 0xe5, 0x63,
0x58, 0x9d, 0x08, 0xc1, 0xe1, 0x84, 0x61, 0x2c, 0x81, 0xbf, 0x65, 0xf6,
0x93, 0x66, 0x8b, 0xe4, 0xcb, 0x3b, 0x62, 0xf6, 0xbd, 0x33, 0x85, 0x5b,
0x03, 0x7e, 0x91, 0x5f, 0xc2, 0xd8, 0xc1, 0x4a, 0xd8, 0xc4, 0x0d, 0x80,
0x10, 0xb5, 0xb3, 0x78, 0x5b, 0x95, 0x4d, 0x12, 0x14, 0xfa, 0xc4, 0x06,
0x67, 0x39, 0x0f, 0xc2, 0x9d, 0x8a, 0x26, 0x26, 0x02, 0x79, 0x9a, 0xb0,
0x51, 0xdc, 0x3a, 0x3f, 0x53, 0x0c, 0x78, 0x1a, 0xf8, 0x1f, 0x90, 0xd6,
0x70, 0xef, 0x98, 0x2b, 0x6d, 0x29, 0xc7, 0x32, 0xbf, 0xfd, 0xe6, 0x32,
0xe2, 0x08, 0x6f, 0xe4, 0x13, 0xce, 0x45, 0x85, 0xd0, 0x48, 0x59, 0x5c,
0x78, 0x5a, 0xa6, 0x72, 0x45, 0x63, 0x3a, 0x0f, 0xde, 0xce, 0x59, 0xc7,
0x4e, 0x6a, 0x3b, 0x69, 0x37, 0x16, 0x73, 0x09, 0xed, 0x9b, 0xe4, 0x07,
0x10, 0x3d, 0x58, 0x81, 0x53, 0xc4, 0x0a, 0xc6, 0x5a, 0x68, 0x9d, 0x44,
0x06, 0x5e, 0xac, 0x09, 0xc2, 0x7a, 0x03, 0x40, 0x12, 0x9a, 0xf4, 0x14,
0x65, 0xdd, 0x4a, 0x47, 0x10, 0x1f, 0x5d, 0x58, 0x16, 0x06, 0x80, 0x81,
0xa8, 0xfa, 0x0f, 0x66, 0xa0, 0xef, 0xce, 0x9a, 0xbc, 0x35, 0x9e, 0xb7,
0x28, 0x47, 0x44, 0x82, 0x78, 0x02, 0xad, 0x2a, 0x0b, 0x19, 0x7f, 0x13,
0xb3, 0x20, 0x4a, 0xd8, 0xd4, 0xd2, 0x96, 0x60, 0xa2, 0x64, 0x48, 0x66,
0x65, 0x2b, 0x99, 0xd5, 0x35, 0xde, 0xec, 0xca, 0x14, 0xfb, 0x9d, 0x55,
0x7b, 0x62, 0x68, 0x73, 0xf7, 0x82, 0xed, 0x25, 0x92, 0x85, 0x0b, 0xaa,
0xc8, 0xf8, 0x1c, 0xb0, 0xb4, 0xcb, 0x58, 0x68, 0x19, 0x2f, 0x61, 0xb3,
0x66, 0xde, 0x12, 0x6b, 0x0d, 0xef, 0x5a, 0xb9, 0x47, 0x8a, 0xd5, 0x91,
0x41, 0x48, 0x92, 0xdc, 0x0c, 0x03, 0xf5, 0x06, 0xe2, 0xc7, 0xe2, 0x6c,
0xc2, 0x80, 0x80, 0x27, 0xec, 0x56, 0x8a, 0x48, 0xb8, 0xc5, 0x32, 0x84,
0xd6, 0x09, 0x3b, 0xe3, 0x96, 0xe6, 0x2e, 0xf6, 0x76, 0x3e, 0xff, 0xd5,
0x11, 0x03, 0xcf, 0x66, 0xba, 0x84, 0x16, 0x58, 0xe9, 0x43, 0x6e, 0x6e,
0x28, 0x47, 0x76, 0x72, 0x95, 0x26, 0x55, 0x59, 0x26, 0xf7, 0xed, 0xd6,
0x06, 0xe5, 0xe0, 0x81, 0x2d, 0xd5, 0x15, 0x09, 0x56, 0xdd, 0x78, 0x4b,
0x39, 0x81, 0x93, 0xbb, 0x8e, 0x8e, 0x1c, 0x93, 0xc3, 0xbb, 0xbd, 0xeb,
0xcc, 0x6d, 0x2e, 0x79, 0xe7, 0x1b, 0x24, 0x79, 0x8c, 0x04, 0x63, 0x27,
0xfd, 0x7e, 0x9a, 0x23, 0x1c, 0xac, 0x21, 0x2a, 0x89, 0x5e, 0xa2, 0x98,
0x8a, 0x87, 0x2c, 0xa5, 0x10, 0x20, 0x2c, 0xea, 0x15, 0x9a, 0xd7, 0x5c,
0x33, 0xb4, 0x88, 0x90, 0x59, 0x33, 0xff, 0x19, 0x9c, 0x7a, 0x54, 0x59,
0x78, 0x0f, 0x63, 0x84, 0x40, 0xd2, 0x37, 0xc3, 0x98, 0x6c, 0x05, 0x7c,
0x38, 0x01, 0xf6, 0x58, 0x04, 0x7b, 0x8c, 0x53, 0xea, 0xdf, 0x56, 0x14,
0x49, 0xe2, 0x54, 0x1d, 0x1d, 0xe7, 0xc8, 0x23, 0x7b, 0x14, 0x44, 0xdb,
0x1c, 0x3b, 0xc1, 0x27, 0x9e, 0x12, 0x02, 0xf9, 0x0d, 0x87, 0x73, 0x1b,
0x7f, 0xa4, 0x08, 0x2b, 0x17, 0x11, 0xbd, 0xbc, 0xaa, 0x58, 0xfe, 0x24,
0xb1, 0xe5, 0x3a, 0x9a, 0xb0, 0x95, 0xb4, 0xe7, 0x47, 0x1c, 0x0e, 0x78,
0xf1, 0x35, 0x34, 0x83, 0xcd, 0x6a, 0x53, 0x51, 0x92, 0x7f, 0x2d, 0x65,
0x3d, 0x3a, 0xbd, 0x81, 0xd7, 0x60, 0xfa, 0xf4, 0x15, 0xdd, 0x11, 0xd2,
0x21, 0x94, 0x86, 0x0f, 0x8a, 0x16, 0x86, 0x69, 0xbe, 0x47, 0x97, 0x7d,
0x8e, 0xe2, 0x83, 0x68, 0xf1, 0x34, 0x4f, 0x86, 0x0e, 0xe2, 0xc6, 0x1b,
0x2d, 0x51, 0xe5, 0x34, 0x28, 0xf8, 0x41, 0x11, 0xc2, 0xf4, 0x8f, 0x29,
0x64, 0x79, 0x2c, 0x08, 0x00, 0xb8, 0x83, 0x2d, 0x66, 0x27, 0x49, 0xc8,
0xbb, 0x75, 0xea, 0x87, 0xfe, 0xb1, 0xf0, 0x73, 0xd2, 0x47, 0x93, 0x44,
0xb0, 0x0d, 0x64, 0x10, 0x50, 0x73, 0xc0, 0xff, 0x83, 0xba, 0xdd, 0x9c,
0xd2, 0x63, 0x8e, 0x92, 0xda, 0x12, 0xfe, 0x17, 0xfe, 0xb2, 0x31, 0x82,
0xa7, 0x9c, 0xa3, 0xff, 0x7b, 0xf9, 0x03, 0x7a, 0xd9, 0xe7, 0x74, 0x49,
0xd2, 0xf2, 0x5d, 0x5e, 0x97, 0x52, 0xf0, 0xc0, 0x90, 0xa2, 0x50, 0xb3,
0x21, 0xd9, 0x42, 0xdb, 0x6c, 0x02, 0x38, 0xb1, 0xac, 0xc6, 0x4a, 0xd3,
0xd6, 0xa4, 0x35, 0x3d, 0xef, 0xce, 0xc6, 0xda, 0x02, 0x38, 0xea, 0xa7,
0xf8, 0xa1, 0x8e, 0x03, 0xa2, 0xd5, 0x0b, 0x9a, 0x04, 0xa6, 0x40, 0x34,
0x58, 0x0d, 0xe9, 0x42, 0x13, 0x30, 0x18, 0x55, 0x1f, 0x33, 0xdb, 0x49,
0x0f, 0xb2, 0x15, 0x43, 0x99, 0x18, 0x3e, 0x5a, 0x64, 0xdc, 0x85, 0xc1,
0x3b, 0x81, 0x73, 0x64, 0x5b, 0x49, 0x2f, 0x4d, 0xa7, 0x97, 0xff, 0x2e,
0x73, 0x7b, 0x09, 0x24, 0x53, 0x90, 0x84, 0x13, 0x9e, 0xef, 0xb1, 0x30,
0x93, 0x84, 0x07, 0xc8, 0x2c, 0x0b, 0xb3, 0xb1, 0x2a, 0x44, 0xcc, 0x86,
0x3d, 0x7d, 0xfb, 0x91, 0x62, 0xa5, 0xb7, 0xe8, 0x28, 0xa6, 0x84, 0xcc,
0xdc, 0xf9, 0x3f, 0x41, 0xa3, 0x91, 0xc1, 0x24, 0x11, 0xeb, 0xbf, 0x11,
0x4a, 0x92, 0x90, 0x0d, 0x67, 0x8b, 0x41, 0x24, 0x53, 0xf7, 0xbe, 0xae,
0xa1, 0x48, 0x61, 0x3d, 0x8f, 0xcf, 0x2d, 0xdb, 0xfd, 0x1e, 0xc0, 0x89,
0x93, 0xf3, 0x0a, 0x49, 0x42, 0xfe, 0xe3, 0x3c, 0x38, 0xf1, 0x17, 0x54,
0x4f, 0x67, 0xf8, 0x30, 0xd9, 0x1b, 0x14, 0x65, 0x2e, 0xcc, 0xde, 0xaf,
0x2b, 0xd7, 0x2a, 0xef, 0x9f, 0xa7, 0x28, 0x9f, 0xb9, 0xe2, 0xf5, 0xeb,
0x7b, 0x27, 0x3b, 0x8b, 0x86, 0x07, 0xca, 0x2a, 0x0c, 0x75, 0x46, 0x66,
0x9d, 0xa5, 0x6a, 0x3f, 0x5e, 0xdc, 0x49, 0xcf, 0xbd, 0xa2, 0xff, 0x07,
0x79, 0xa4, 0xff, 0x7d, 0xfc, 0x47, 0x6b, 0x34, 0xdc, 0xc7, 0xeb, 0x53,
0x65, 0x51, 0x71, 0xda, 0x49, 0x20, 0xea, 0xe5, 0xd3, 0xb0, 0xea, 0x26,
0x1b, 0x82, 0xcf, 0x81, 0x2d, 0x8c, 0x47, 0x0a, 0xfe, 0x8a, 0x6c, 0x15,
0xc1, 0xc4, 0x47, 0x82, 0x60, 0x01, 0x3c, 0x50, 0x20, 0x5f, 0xef, 0xe3,
0xdf, 0xa9, 0xf9, 0x2e, 0xb2, 0xe6, 0xd0, 0xa9, 0xb1, 0x7e, 0x98, 0xcd,
0x39, 0x40, 0xe1, 0x2d, 0xb6, 0xe0, 0x70, 0x44, 0xb0, 0x49, 0xa7, 0xea,
0xbb, 0xc8, 0xaa, 0xcd, 0x8d, 0x62, 0x28, 0x7f, 0xab, 0x12, 0x6d, 0x0f,
0x65, 0xc1, 0x4c, 0x00, 0x72, 0x08, 0xd9, 0xd5, 0x48, 0x60, 0x7c, 0xe2,
0xc3, 0x05, 0x7b, 0x43, 0x60, 0x83, 0xd2, 0x38, 0x5a, 0xf7, 0x66, 0xfc,
0x3c, 0x16, 0x12, 0x0e, 0x1f, 0xc8, 0x62, 0x6d, 0x91, 0x6c, 0xd2, 0x7a,
0x68, 0x53, 0x04, 0xfc, 0x05, 0x1c, 0x6d, 0xa9, 0xcb, 0xf5, 0xe0, 0x54,
0x08, 0xf8, 0xdf, 0x06, 0xf6, 0x18, 0xbb, 0x69, 0x49, 0xde, 0x70, 0xc2,
0x21, 0x12, 0x5c, 0xca, 0xd0, 0x79, 0xc8, 0x49, 0x65, 0x6d, 0x46, 0xf0,
0xf4, 0xa0, 0x67, 0xf8, 0x3b, 0x68, 0x01, 0x83, 0x24, 0x89, 0x38, 0xe6,
0xc4, 0x2d, 0x8f, 0x32, 0x1e, 0xeb, 0xc8, 0xb8, 0xc6, 0x15, 0x7e, 0x68,
0x9a, 0xa6, 0x0b, 0x03, 0x3f, 0x25, 0x35, 0x11, 0x1a, 0x52, 0xe4, 0x99,
0x02, 0x77, 0x0a, 0xe0, 0x20, 0x6c, 0xd0, 0x61, 0x78, 0xb4, 0xe4, 0xd8,
0xcb, 0x31, 0x51, 0x3c, 0xce, 0xb0, 0x3b, 0x65, 0xdf, 0x32, 0x09, 0xda,
0x1b, 0x94, 0xeb, 0xa4, 0xbb, 0xf6, 0x06, 0x30, 0x40, 0xf9, 0x9e, 0x22,
0x8c, 0x40, 0x3a, 0xc4, 0xe4, 0x1b, 0x66, 0xf0, 0xbf, 0x72, 0xfe, 0xf4,
0x69, 0xdd, 0xf9, 0xbc, 0xbc, 0xc6, 0x37, 0x39, 0xa9, 0xf7, 0x16, 0xe2,
0xe8, 0xd2, 0x2a, 0x4d, 0x36, 0x5a, 0xd2, 0x0c, 0xbe, 0x1b, 0x15, 0x8c,
0x44, 0x01, 0xea, 0x35, 0x53, 0x05, 0x80, 0xd3, 0x13, 0x36, 0x89, 0x04,
0x21, 0xce, 0xd0, 0xbd, 0x8d, 0xe4, 0x77, 0x2c, 0x7b, 0x48, 0x4c, 0x2c,
0x05, 0x4f, 0x29, 0xb2, 0xc1, 0x04, 0x36, 0xde, 0x52, 0x16, 0x48, 0xab,
0xc0, 0xd1, 0xfa, 0x84, 0xdf, 0x92, 0xe8, 0x69, 0xcb, 0x35, 0x2d, 0xe3,
0xc9, 0xc4, 0xd3, 0x36, 0xc5, 0xc8, 0x62, 0x05, 0x55, 0xe8, 0xd1, 0x52,
0x73, 0x0b, 0xc9, 0xd3, 0x4e, 0x80, 0x5b, 0x8f, 0x65, 0x13, 0x12, 0x01,
0x90, 0x38, 0xd3, 0x93, 0x37, 0x12, 0x36, 0xd5, 0x90, 0xdc, 0x10, 0xae,
0x5a, 0x70, 0xa4, 0xc5, 0x0d, 0x41, 0xa3, 0x0d, 0xbb, 0x2e, 0xac, 0xb3,
0x80, 0xe2, 0x59, 0x88, 0x2d, 0x9d, 0x69, 0x8e, 0xa0, 0xd8, 0xf9, 0x3a,
0x19, 0x51, 0x16, 0xe7, 0xe6, 0x41, 0xb1, 0x55, 0x7a, 0xd2, 0xc9, 0x52,
0xa6, 0x53, 0xaf, 0xc3, 0xf8, 0x80, 0x2d, 0x5f, 0x95, 0x9b, 0x90, 0x93,
0xa4, 0x3e, 0x80, 0xb0, 0x89, 0xd1, 0x64, 0x38, 0x4d, 0x92, 0x46, 0xfe,
0x69, 0xd6, 0xbf, 0x69, 0x4d, 0xa0, 0xe3, 0x5b, 0x78, 0x59, 0xe3, 0x60,
0x8f, 0xd6, 0x63, 0xe3, 0xd6, 0xcd, 0x92, 0xf7, 0xda, 0x39, 0x46, 0x21,
0x09, 0xaf, 0xd7, 0x1c, 0x3f, 0x63, 0x28, 0x8a, 0x7d, 0xc0, 0x8c, 0x3c,
0xc1, 0x45, 0x46, 0x36, 0x00, 0xf2, 0xfe, 0x21, 0xe4, 0xec, 0x8f, 0xda,
0xb7, 0x77, 0x3e, 0xc7, 0x74, 0xec, 0x5d, 0x52, 0x96, 0xf9, 0xfa, 0x6b,
0x47, 0x1d, 0x66, 0xb3, 0xd6, 0x33, 0xe6, 0xce, 0xfa, 0xcd, 0xae, 0x1d,
0x31, 0x04, 0xef, 0xd5, 0x83, 0x97, 0xd4, 0x87, 0x8d, 0x5e, 0xd8, 0x77,
0x07, 0x34, 0x4b, 0x07, 0x7f, 0xfa, 0xe8, 0x26, 0x0d, 0xc5, 0xd8, 0xc9,
0x27, 0xfa, 0xa4, 0xc0, 0xbc, 0xb5, 0x41, 0xf1, 0x97, 0x67, 0x27, 0x49,
0xcb, 0xaf, 0x19, 0xdc, 0x58, 0xdc, 0x98, 0xbe, 0xeb, 0xf3, 0xf5, 0xc2,
0xd9, 0xb5, 0x4e, 0x86, 0xf7, 0x6f, 0x48, 0xcf, 0x92, 0xf6, 0x23, 0xdd,
0xe5, 0x1a, 0x9e, 0x9d, 0x9d, 0x9b, 0xb8, 0xaa, 0xfb, 0xdb, 0xfd, 0xa2,
0x25, 0x6b, 0x9a, 0xf0, 0xed, 0xf3, 0x8c, 0x6f, 0x73, 0x8c, 0x70, 0x04,
0xb9, 0x05, 0x2b, 0xb9, 0x04, 0xcd, 0xb0, 0xdb, 0x6b, 0x12, 0x03, 0xcd,
0xf4, 0xf7, 0x26, 0xa0, 0x28, 0xc9, 0xcd, 0x49, 0x28, 0x09, 0x9c, 0x02,
0x69, 0xd1, 0xb2, 0x0d, 0xdf, 0x41, 0x9f, 0x04, 0xd9, 0x9b, 0x04, 0x98,
0xfc, 0x11, 0x7c, 0x1d, 0x03, 0x3c, 0x7c, 0xa7, 0x52, 0xc1, 0x9c, 0x32,
0x21, 0x62, 0xd1, 0xfa, 0x51, 0xfc, 0xf9, 0x28, 0x14, 0xa0, 0x26, 0x05,
0x56, 0x89, 0xb8, 0xd8, 0x74, 0xc0, 0x27, 0xd6, 0x71, 0x66, 0xbf, 0xb9,
0x9b, 0xb8, 0x40, 0x3e, 0x34, 0x5a, 0x22, 0x24, 0xb0, 0xeb, 0x31, 0x7f,
0xe2, 0xb8, 0x29, 0x9e, 0x49, 0x5a, 0x74, 0x03, 0x73, 0x94, 0x8f, 0x72,
0x80, 0xdc, 0xfa, 0x9d, 0x3b, 0x4a, 0x36, 0xc4, 0x44, 0x36, 0x18, 0x84,
0x3f, 0x75, 0xf7, 0xfc, 0x9a, 0xe3, 0x45, 0x18, 0x83, 0x9c, 0x11, 0x7a,
0xd3, 0xa1, 0x1c, 0x7d, 0x21, 0x1a, 0x20, 0x36, 0x80, 0x05, 0x7d, 0x0d,
0x38, 0x72, 0x38, 0x7c, 0x0d, 0x67, 0xaf, 0x0f, 0x43, 0x6a, 0xc8, 0xa9,
0x9d, 0xe8, 0x1a, 0x29, 0xa2, 0xea, 0x4e, 0x8f, 0xac, 0x50, 0xe4, 0x88,
0x2a, 0x3e, 0xaa, 0x99, 0x28, 0x78, 0x55, 0x8d, 0xaa, 0xd1, 0xa3, 0x9a,
0x5f, 0x06, 0x38, 0x76, 0x06, 0x35, 0xf1, 0xb2, 0x71, 0x8e, 0xd1, 0x5a,
0x08, 0xa6, 0x8b, 0xdb, 0xd8, 0xeb, 0x24, 0xa6, 0xfc, 0x67, 0x76, 0x3b,
0x5c, 0xb5, 0x8d, 0xea, 0x28, 0x35, 0xaa, 0x66, 0x22, 0x8e, 0x23, 0x6a,
0x44, 0x5e, 0xf9, 0x8b, 0xb4, 0x6b, 0x4c, 0x45, 0xdd, 0x7d, 0x12, 0xda,
0x35, 0x5d, 0x58, 0x4a, 0xf6, 0x6e, 0x69, 0xf9, 0xf7, 0x87, 0xb6, 0x72,
0x5b, 0x64, 0x2f, 0xca, 0x7f, 0xbe, 0x8b, 0xd2, 0x82, 0x5a, 0xda, 0xb0,
0xff, 0xb0, 0x92, 0x67, 0x42, 0xb5, 0x0a, 0xdd, 0x93, 0x6a, 0x9e, 0x4c,
0xaa, 0xc1, 0x29, 0xd5, 0x06, 0x4e, 0x93, 0xd8, 0x72, 0xe3, 0xde, 0x32,
0x65, 0x84, 0x7c, 0x05, 0x8e, 0x88, 0x05, 0x25, 0x01, 0x7a, 0x1f, 0xba,
0xf9, 0xfb, 0xf1, 0xb1, 0x45, 0xd4, 0xc6, 0x6f, 0xf0, 0x14, 0x5b, 0xe8,
0xa1, 0x2d, 0x9c, 0xb9, 0xac, 0x8c, 0xcc, 0xae, 0x0d, 0x98, 0x8a, 0xd3,
0xf7, 0xa4, 0xf2, 0x2d, 0x07, 0xfa, 0xa3, 0x8f, 0xf4, 0x07, 0x00, 0x99,
0x8f, 0x3a, 0xe3, 0x1f, 0xe8, 0xfa, 0x37, 0x99, 0x6c, 0x94, 0xe1, 0x7e,
0x8c, 0xf9, 0xc6, 0x35, 0xe2, 0x50, 0x79, 0x3e, 0xcc, 0xa0, 0x3f, 0xc8,
0xac, 0xff, 0x2c, 0xe3, 0x8e, 0x65, 0xe2, 0x96, 0xa1, 0xfb, 0x9e, 0x63,
0x78, 0xc4, 0xf0, 0x79, 0xc5, 0x49, 0xd0, 0xdb, 0x67, 0x88, 0xff, 0x8c,
0x0b, 0x1c, 0x64, 0xe0, 0x39, 0x2d, 0x7c, 0xcc, 0x91, 0x72, 0xf3, 0xe6,
0x86, 0x49, 0x75, 0xdd, 0x01, 0xf2, 0x6a, 0xad, 0x55, 0x1b, 0xd4, 0xde,
0x71, 0x84, 0x3c, 0xa8, 0x38, 0x30, 0x99, 0xca, 0xc8, 0x8e, 0xca, 0xff,
0x4c, 0x97, 0x92, 0xcb, 0xf1, 0x60, 0x0c, 0x1a, 0xc9, 0x18, 0x81, 0xb5,
0x6f, 0x74, 0x38, 0x27, 0xd4, 0xe1, 0x44, 0xac, 0x1c, 0xce, 0xfb, 0x9d,
0x1f, 0xb0, 0x69, 0xc3, 0xba, 0x3b, 0xd4, 0xb9, 0xc4, 0xbe, 0x02, 0x14,
0x50, 0x89, 0x69, 0xba, 0xde, 0x06, 0xe3, 0x1b, 0x93, 0x1b, 0x2b, 0xbe,
0x61, 0x91, 0x6e, 0x88, 0x81, 0x4b, 0xcc, 0xa0, 0x51, 0xa3, 0xd7, 0x08,
0x70, 0x2c, 0xfe, 0x1d, 0x5c, 0xde, 0x38, 0x61, 0xc9, 0xb1, 0x54, 0x9a,
0xc6, 0x8a, 0xb6, 0x09, 0x79, 0x2e, 0xd1, 0x38, 0xdd, 0xe9, 0x11, 0x60,
0x42, 0x33, 0xac, 0x1e, 0xf1, 0xaa, 0x25, 0xae, 0xb7, 0xa3, 0x16, 0x42,
0x62, 0x90, 0xa3, 0x0d, 0x67, 0xae, 0xc9, 0xcb, 0xc2, 0xec, 0xdb, 0xa3,
0xd4, 0xe2, 0xd3, 0xe4, 0x45, 0x63, 0x69, 0xc0, 0x87, 0x42, 0xf8, 0x5a,
0xa9, 0x74, 0xe0, 0x06, 0xcd, 0xb4, 0x05, 0x70, 0x75, 0xb8, 0x83, 0x5d,
0xa7, 0xe3, 0xc4, 0x3f, 0xd0, 0x9d, 0x61, 0x48, 0x28, 0x92, 0x7b, 0x92,
0x12, 0x27, 0xca, 0xec, 0x87, 0xdc, 0x5b, 0xf8, 0xc0, 0x28, 0x93, 0x2c,
0x2e, 0xfc, 0x3c, 0x32, 0x23, 0xd0, 0xd0, 0xfd, 0x51, 0xd4, 0xca, 0xc2,
0x46, 0xa0, 0xeb, 0x8c, 0xf5, 0xf0, 0x77, 0xba, 0x0b, 0xfc, 0x8e, 0x7b,
0xe4, 0xe8, 0xc5, 0xde, 0xf5, 0x48, 0xbc, 0x0b, 0x87, 0xff, 0x15, 0x56,
0x13, 0xeb, 0xc1, 0x01, 0xe0, 0x95, 0x08, 0x91, 0xab, 0x10, 0x3d, 0xba,
0x4a, 0x9d, 0xaa, 0x6f, 0x59, 0x6d, 0x29, 0xf2, 0xab, 0x16, 0x3c, 0x54,
0x0a, 0xdc, 0xb1, 0x71, 0x7c, 0x86, 0x65, 0xf1, 0x04, 0xcd, 0xe7, 0x5d,
0x83, 0xd6, 0x42, 0x2f, 0x82, 0x7a, 0x73, 0x9f, 0x49, 0xb3, 0x14, 0x06,
0x12, 0xb9, 0x1d, 0x96, 0xb5, 0xae, 0x82, 0x04, 0xf1, 0x49, 0x23, 0x01,
0xfc, 0xe7, 0xcf, 0xfc, 0xcc, 0x47, 0x8e, 0x8f, 0xe4, 0x46, 0x0e, 0xc9,
0xc0, 0x0b, 0x34, 0x41, 0x8a, 0xed, 0x8b, 0xc8, 0x33, 0x18, 0xbc, 0x51,
0x1c, 0xe2, 0xaf, 0xb5, 0x1c, 0xba, 0x6f, 0x34, 0x43, 0xea, 0xd8, 0x56,
0x9b, 0x43, 0xc9, 0x14, 0xd2, 0x36, 0xa4, 0xa4, 0x17, 0x87, 0x0e, 0x91,
0x80, 0x20, 0xce, 0x88, 0x76, 0xfc, 0x31, 0x76, 0x71, 0x47, 0xee, 0x3a,
0x73, 0xcf, 0x03, 0xaa, 0xe0, 0x8d, 0x0f, 0x59, 0xfc, 0x60, 0xdf, 0x92,
0xf0, 0xc8, 0x93, 0xcb, 0xa9, 0x70, 0x61, 0xec, 0x5f, 0x7e, 0x51, 0xd6,
0x35, 0xb1, 0x45, 0x4b, 0x62, 0xbb, 0xb8, 0x34, 0x83, 0xef, 0xb2, 0x11,
0x97, 0xfb, 0xa7, 0xc4, 0x4a, 0x7f, 0xc1, 0x2d, 0x3c, 0x8c, 0x51, 0x96,
0x94, 0x51, 0xe2, 0x47, 0x5c, 0x00, 0xd7, 0xf0, 0x9e, 0x89, 0x34, 0x87,
0xd4, 0x7e, 0x5e, 0x92, 0xb1, 0x82, 0xaa, 0x0f, 0xb9, 0x95, 0x97, 0xcb,
0xc1, 0x08, 0x8c, 0x0a, 0x25, 0x3e, 0xc8, 0x7a, 0x36, 0xdf, 0x42, 0x8a,
0x71, 0x17, 0xe6, 0x4d, 0x37, 0x6a, 0xac, 0x7b, 0x32, 0xf1, 0x02, 0x36,
0x4a, 0x07, 0x94, 0x46, 0xdf, 0x46, 0x90, 0xd8, 0x68, 0xb7, 0xf4, 0x7c,
0x40, 0x00, 0x8f, 0xf5, 0x2d, 0xaa, 0x2c, 0x00, 0x12, 0x46, 0xf6, 0x61,
0x18, 0xd3, 0x90, 0xf4, 0x75, 0x43, 0x80, 0x84, 0x32, 0x53, 0x74, 0xa9,
0xd1, 0x23, 0xbd, 0x6f, 0xb1, 0xfa, 0x18, 0x76, 0x1f, 0xe8, 0x73, 0x8c,
0xbf, 0x3e, 0x9c, 0xa3, 0x4c, 0xb9, 0x62, 0xb8, 0x78, 0x51, 0x1c, 0x71,
0x86, 0x7e, 0x5f, 0xfa, 0xf9, 0x89, 0x1d, 0x59, 0x58, 0xdd, 0x81, 0x7b,
0xbb, 0x0f, 0xfc, 0x10, 0x8d, 0x61, 0x1d, 0xb7, 0x15, 0x01, 0x54, 0x0c,
0x5e, 0x31, 0x37, 0x83, 0x5f, 0xa6, 0x63, 0x76, 0x08, 0xbb, 0x7a, 0x63,
0x00, 0x53, 0x81, 0x09, 0x8a, 0x67, 0x05, 0x0c, 0x4b, 0xbe, 0x83, 0xc0,
0x5f, 0x12, 0x43, 0xe9, 0x93, 0x03, 0x2f, 0x22, 0x99, 0x97, 0xce, 0xe8,
0x4b, 0x7a, 0x56, 0x36, 0x68, 0x14, 0x3b, 0x97, 0x3a, 0xea, 0x2b, 0x63,
0x63, 0x00, 0xef, 0x50, 0x49, 0x10, 0x15, 0x6c, 0xc4, 0x00, 0xd0, 0x3e,
0x24, 0xbf, 0x13, 0x85, 0x50, 0xa6, 0x4f, 0xe1, 0x90, 0x84, 0x04, 0xff,
0x8c, 0x12, 0x8f, 0xdf, 0x3b, 0xda, 0x82, 0x79, 0xc9, 0xa2, 0x1b, 0x04,
0xee, 0xc3, 0x16, 0xc8, 0x05, 0x2c, 0xc1, 0x8d, 0x36, 0xb9, 0xad, 0x95,
0xb0, 0x76, 0x3d, 0xfc, 0x86, 0xa7, 0xcc, 0x66, 0x70, 0x95, 0x41, 0xcf,
0xc2, 0x92, 0xa4, 0x42, 0x7f, 0x27, 0xbc, 0x46, 0x84, 0x5d, 0xcd, 0x21,
0xb3, 0xa5, 0x73, 0x8f, 0xc8, 0x04, 0xd8, 0x4a, 0x7b, 0x00, 0x46, 0x30,
0xe3, 0x37, 0x11, 0xbc, 0x5e, 0xeb, 0x79, 0x21, 0xca, 0x00, 0x59, 0x31,
0x34, 0x29, 0xd3, 0xdf, 0x4a, 0xe3, 0xf7, 0x4c, 0xf1, 0xf0, 0x6c, 0x62,
0x41, 0xd1, 0x8b, 0x17, 0x11, 0x47, 0xa7, 0x87, 0xce, 0x3a, 0xcc, 0xbc,
0xb0, 0xe8, 0x4f, 0x2e, 0x78, 0xbd, 0x7c, 0xda, 0x56, 0x9d, 0x35, 0xa4,
0x60, 0xf7, 0x96, 0x25, 0x1e, 0xdf, 0x6f, 0x62, 0xbe, 0xd6, 0xb0, 0x59,
0x77, 0x64, 0xfc, 0x4a, 0x5a, 0xa2, 0x0a, 0xc7, 0xda, 0xde, 0xa1, 0x14,
0x08, 0x0f, 0x94, 0x57, 0x28, 0xe5, 0x36, 0xa8, 0x94, 0xdb, 0x37, 0x2a,
0x25, 0xc4, 0x80, 0xf0, 0xc3, 0x25, 0x30, 0xd4, 0xe6, 0x64, 0x48, 0x47,
0x6b, 0x50, 0x80, 0xd9, 0x23, 0x1d, 0xff, 0x37, 0xa8, 0x46, 0x43, 0xaf,
0x52, 0x4d, 0x7f, 0x2a, 0x8e, 0x8d, 0x10, 0x05, 0xd1, 0x8a, 0x3f, 0x57,
0x4d, 0x1a, 0xfa, 0x38, 0x35, 0x99, 0x9e, 0xd2, 0x0a, 0x54, 0xc3, 0x8f,
0xa9, 0xb8, 0x92, 0xd9, 0xa1, 0x2b, 0x3e, 0x2b, 0x98, 0xb6, 0xea, 0x8e,
0xde, 0x14, 0x1c, 0xc7, 0x0e, 0x53, 0x3f, 0xc2, 0xb5, 0x46, 0x4a, 0xfe,
0xe2, 0x5b, 0x55, 0x9b, 0x0d, 0x38, 0xeb, 0x6a, 0xdf, 0x84, 0xa6, 0xc8,
0x65, 0x38, 0xa8, 0xd5, 0xc2, 0x07, 0x7d, 0xbd, 0x77, 0x97, 0xf1, 0x3f,
0x1d, 0xa4, 0x79, 0x7e, 0xf1, 0xbf, 0xb3, 0x48, 0x33, 0x70, 0x39, 0x18,
0x13, 0x1c, 0x29, 0x06, 0x15, 0xf3, 0x64, 0x4b, 0x38, 0x3b, 0xd5, 0x10,
0xce, 0xf2, 0xa9, 0x12, 0x30, 0x9d, 0xc8, 0xfd, 0xf8, 0xdd, 0xd7, 0x3f,
0xa7, 0x60, 0x69, 0x7c, 0x02, 0x5f, 0xc9, 0x13, 0xf8, 0xf1, 0xf5, 0xcf,
0xdf, 0x24, 0x73, 0x13, 0x31, 0xed, 0xf4, 0xc4, 0x2c, 0x0d, 0x6f, 0x55,
0x4b, 0xd3, 0x17, 0x1e, 0x30, 0xcf, 0xa4, 0xb9, 0x1f, 0xa1, 0xe4, 0x67,
0xa0, 0x4d, 0x0a, 0x8f, 0xcc, 0x8e, 0x0e, 0x06, 0xe2, 0x9e, 0x5c, 0x80,
0x1d, 0x74, 0xa4, 0x09, 0x09, 0xf2, 0xc2, 0x01, 0xf3, 0x27, 0xd6, 0x99,
0xf9, 0x93, 0xce, 0x36, 0xc1, 0x2b, 0xd6, 0x9e, 0xbd, 0xcc, 0x04, 0x8b,
0x8b, 0x58, 0xcb, 0xe7, 0x39, 0xe0, 0x61, 0x2f, 0xb0, 0x62, 0xe7, 0xe6,
0x2f, 0x80, 0xc7, 0x68, 0x01, 0x2c, 0x53, 0x6f, 0xc7, 0x39, 0xba, 0x76,
0xf6, 0xbc, 0x21, 0x8b, 0x5e, 0x05, 0xc6, 0x5d, 0xa8, 0x1f, 0x42, 0x52,
0x4b, 0x90, 0xef, 0x74, 0x88, 0x49, 0x94, 0xb9, 0x30, 0x96, 0x20, 0x7f,
0x83, 0x47, 0x7d, 0x8e, 0xbb, 0xe3, 0x96, 0x90, 0x9e, 0x19, 0xe9, 0x39,
0x6c, 0x05, 0xdb, 0xd9, 0xed, 0xec, 0x01, 0xfe, 0x95, 0x85, 0xa5, 0xb9,
0xfb, 0xc5, 0xe8, 0xae, 0xc5, 0x39, 0xec, 0xb9, 0xe3, 0x64, 0x96, 0x71,
0xc2, 0xce, 0x8d, 0x71, 0x66, 0x9f, 0xfd, 0xd6, 0x69, 0x1a, 0xb3, 0x61,
0xbd, 0x7f, 0xfd, 0x18, 0x9f, 0xcc, 0x63, 0x14, 0x7a, 0xbb, 0x9a, 0x75,
0xf7, 0xff, 0x11, 0x6b, 0x32, 0x09, 0x47, 0xf5, 0x18, 0x11, 0x2a, 0x2d,
0x11, 0x31, 0x29, 0x28, 0xf3, 0xd5, 0x62, 0xa9, 0x43, 0x6b, 0xcc, 0x1e,
0x09, 0xad, 0xb3, 0x22, 0x4d, 0xfb, 0xfa, 0xb3, 0x75, 0xa1, 0x99, 0xbc,
0x28, 0xd8, 0x8b, 0x22, 0x92, 0x9b, 0xe1, 0x18, 0xcb, 0x7b, 0x57, 0xdc,
0x44, 0xdd, 0xf2, 0xa0, 0x6e, 0x01, 0x2a, 0x45, 0xa0, 0xe2, 0x62, 0x29,
0xe1, 0x45, 0xf4, 0x39, 0xfa, 0x42, 0xfa, 0x3f, 0x00, 0x33, 0xfc, 0x14,
0xf6, 0xa1, 0x5e, 0x00, 0x00
0x1f, 0x8b, 0x08, 0x08, 0x79, 0x1c, 0x96, 0x5d, 0x04, 0x00, 0x65, 0x64,
0x69, 0x74, 0x2e, 0x68, 0x74, 0x6d, 0x00, 0xed, 0x1d, 0x6b, 0x57, 0xea,
0x46, 0xf0, 0x7b, 0xcf, 0xe9, 0x7f, 0x48, 0xd3, 0x87, 0x50, 0x9e, 0xa2,
0xd7, 0x2a, 0x6a, 0x5b, 0x40, 0x40, 0x45, 0x8a, 0x08, 0x2a, 0xda, 0xd7,
0x09, 0xc9, 0x02, 0xd1, 0x90, 0xc4, 0x24, 0x08, 0x7a, 0x6b, 0x7f, 0x7b,
0x67, 0x1f, 0x79, 0x27, 0x10, 0xd4, 0x3e, 0x4f, 0xb9, 0xed, 0x25, 0xec,
0xce, 0xcc, 0xce, 0xcc, 0xce, 0xce, 0xce, 0xce, 0xee, 0xe6, 0x1e, 0x7c,
0x76, 0xd4, 0xa9, 0xf5, 0x6f, 0xce, 0xeb, 0xdc, 0xc4, 0x9a, 0x2a, 0xdf,
0x7e, 0xfa, 0xc9, 0x01, 0xfe, 0xe6, 0x14, 0x41, 0x1d, 0x1f, 0xf2, 0x48,
0xe5, 0xa1, 0x84, 0xe3, 0x0e, 0x26, 0x48, 0x90, 0xc8, 0x13, 0x3c, 0x5b,
0xb2, 0xa5, 0xa0, 0x6f, 0x7b, 0xe7, 0x27, 0x8d, 0x46, 0x8f, 0xab, 0x4b,
0xb2, 0xa5, 0x19, 0x07, 0x05, 0x52, 0x68, 0x43, 0x98, 0xd6, 0x93, 0x82,
0x38, 0xeb, 0x49, 0x47, 0x87, 0xbc, 0x85, 0x16, 0x56, 0x41, 0x34, 0x4d,
0x9e, 0x9b, 0x22, 0x49, 0x16, 0x0e, 0x79, 0x53, 0x34, 0x10, 0xa3, 0x4b,
0x3e, 0x79, 0x51, 0x53, 0x31, 0x50, 0x1b, 0xa9, 0x33, 0xee, 0x23, 0x94,
0xb2, 0xcf, 0x73, 0x4e, 0x56, 0x25, 0xb4, 0x28, 0x73, 0x5b, 0xc5, 0xe2,
0xbe, 0x5b, 0xac, 0x6b, 0xa6, 0x6c, 0xc9, 0x9a, 0x5a, 0xe6, 0x84, 0xa1,
0xa9, 0x29, 0x33, 0x0b, 0x79, 0x2a, 0x15, 0x34, 0xb2, 0xca, 0xdc, 0x07,
0x7d, 0xe1, 0x29, 0x1b, 0x6a, 0x86, 0x84, 0x8c, 0x32, 0xb7, 0xa9, 0x2f,
0x38, 0x40, 0x90, 0x25, 0xee, 0xf3, 0xed, 0xed, 0x6d, 0x2f, 0x80, 0x20,
0xde, 0x8f, 0x0d, 0x6d, 0xa6, 0x4a, 0x39, 0x51, 0x53, 0x34, 0x00, 0xfd,
0xbc, 0xf1, 0x01, 0xff, 0xf1, 0xc0, 0x48, 0xb2, 0xa9, 0x2b, 0xc2, 0x53,
0x99, 0x53, 0x35, 0x15, 0xf9, 0x88, 0x2f, 0x72, 0xe6, 0x44, 0x90, 0xb4,
0x79, 0x99, 0x2b, 0xc2, 0x9f, 0xcd, 0x22, 0xb4, 0x62, 0x8c, 0x87, 0x42,
0x8a, 0x2b, 0x66, 0xd9, 0x7f, 0xf9, 0x6d, 0x2e, 0xed, 0x41, 0x19, 0x81,
0xb8, 0x39, 0x53, 0x7e, 0x46, 0xc0, 0x52, 0xc9, 0xe6, 0xd4, 0xad, 0x19,
0x09, 0x53, 0x59, 0x81, 0x86, 0x4c, 0x41, 0x35, 0x73, 0x26, 0x32, 0xe4,
0x51, 0x10, 0x62, 0x8e, 0xe4, 0xf1, 0xc4, 0x2a, 0x0f, 0x35, 0x45, 0x72,
0xaa, 0x5e, 0x22, 0xb5, 0x39, 0x53, 0xbc, 0x0a, 0x55, 0x64, 0x13, 0x1a,
0xc6, 0x5d, 0x13, 0x12, 0xc3, 0xd2, 0x74, 0xe0, 0x3f, 0xa0, 0x48, 0x7f,
0xc9, 0x54, 0x30, 0xc6, 0xb2, 0xea, 0x2f, 0xd3, 0x05, 0x49, 0x92, 0xd5,
0x31, 0x14, 0x2e, 0x67, 0x04, 0x9a, 0xc6, 0x8c, 0x84, 0xbb, 0xd0, 0x40,
0x8a, 0x60, 0xc9, 0x8f, 0xc8, 0xdb, 0x8e, 0xac, 0xe6, 0xe6, 0xb2, 0x64,
0x4d, 0xca, 0xdc, 0x4e, 0xd1, 0xa7, 0x1e, 0x71, 0x66, 0x98, 0xd0, 0x3b,
0x80, 0x2e, 0x03, 0x65, 0x63, 0x45, 0x93, 0xa6, 0x2e, 0xa8, 0xde, 0x46,
0x69, 0xd7, 0xb2, 0xbe, 0x0f, 0xf7, 0xab, 0xac, 0x2a, 0xb2, 0x8a, 0x72,
0x43, 0x45, 0x13, 0xef, 0xa3, 0x24, 0xdc, 0xd1, 0x17, 0x2b, 0x65, 0x2c,
0x4f, 0xb4, 0x47, 0x64, 0x70, 0x1f, 0x3d, 0x16, 0xc5, 0x1a, 0x5c, 0x81,
0xc2, 0x98, 0x75, 0x78, 0xac, 0xd7, 0xeb, 0x0e, 0x8a, 0x8b, 0x68, 0x9a,
0x39, 0x0b, 0x86, 0xce, 0xa3, 0x8c, 0xe6, 0xd0, 0xb3, 0x59, 0x7f, 0x09,
0x51, 0x71, 0x88, 0xef, 0xd5, 0x5d, 0x18, 0x36, 0x0a, 0x57, 0xc8, 0xe8,
0xa6, 0x65, 0x55, 0x9f, 0x59, 0xdc, 0xc7, 0x84, 0x23, 0x52, 0xd3, 0x05,
0x51, 0xb6, 0x9e, 0xa0, 0xd1, 0xd5, 0x94, 0x3f, 0xfa, 0x0d, 0x1d, 0x33,
0x64, 0x4c, 0x05, 0x85, 0xdb, 0xc4, 0x43, 0xf7, 0x0a, 0x19, 0x92, 0xa0,
0x0a, 0x59, 0xae, 0x62, 0xc8, 0x02, 0x48, 0xdf, 0x8b, 0x1a, 0x1f, 0xb9,
0xa9, 0xf6, 0x9c, 0x9b, 0x41, 0x29, 0xd4, 0x28, 0x48, 0xb4, 0x42, 0x86,
0x0e, 0x83, 0x67, 0x78, 0x2f, 0x5b, 0x4b, 0x61, 0x3c, 0x75, 0x49, 0x75,
0x12, 0x67, 0x6c, 0xc5, 0xe2, 0x28, 0x99, 0x01, 0xc7, 0x93, 0xb5, 0x8d,
0xca, 0x25, 0x83, 0xcd, 0x27, 0x27, 0x21, 0x51, 0x33, 0x04, 0xaa, 0x76,
0xb0, 0x33, 0x64, 0x28, 0x72, 0x12, 0x46, 0x69, 0xe7, 0x65, 0xc0, 0xbd,
0x0f, 0x91, 0x02, 0xdf, 0xc4, 0x43, 0x84, 0x0d, 0x84, 0xfc, 0x29, 0x81,
0x77, 0x4a, 0x4a, 0xf1, 0x77, 0x42, 0x29, 0x34, 0xae, 0x92, 0xea, 0x8f,
0xb0, 0x93, 0x8d, 0x2a, 0x2c, 0x97, 0x87, 0x68, 0xa4, 0x19, 0x88, 0xfb,
0xf8, 0x06, 0x3d, 0x12, 0x1e, 0xcb, 0xc0, 0x93, 0x30, 0x54, 0x90, 0x64,
0x8b, 0x1f, 0x45, 0x52, 0x42, 0x23, 0x61, 0xa6, 0x58, 0x51, 0x06, 0x9c,
0xdf, 0x49, 0xda, 0x90, 0x38, 0x41, 0xe2, 0x3d, 0x92, 0xca, 0xaa, 0x66,
0xa5, 0x9c, 0x56, 0xd3, 0xf1, 0x3a, 0x22, 0x4e, 0x67, 0x35, 0xf1, 0xf5,
0x94, 0xe4, 0xf5, 0x41, 0x33, 0x43, 0x49, 0xf1, 0x92, 0x60, 0x09, 0x65,
0x79, 0x2a, 0x8c, 0x51, 0x41, 0x57, 0xc7, 0xfb, 0x43, 0xc1, 0x44, 0x3b,
0xdb, 0x59, 0xf9, 0xaa, 0xda, 0xb9, 0x98, 0x17, 0x5b, 0xcd, 0xb1, 0x56,
0x81, 0xcf, 0x0f, 0xbd, 0xcb, 0x49, 0xfd, 0x72, 0x0c, 0x4f, 0x55, 0xfc,
0xb3, 0x36, 0xae, 0x55, 0x6e, 0xf0, 0x43, 0xa3, 0x83, 0xe6, 0x97, 0xf8,
0xa1, 0x39, 0xb8, 0x68, 0x5c, 0x1f, 0x5f, 0xf4, 0x87, 0xa5, 0xdb, 0xa2,
0x54, 0x6a, 0x3c, 0xdd, 0x76, 0xab, 0xd5, 0xdb, 0xe6, 0x9e, 0x7c, 0xdb,
0xab, 0x9e, 0x0e, 0xaf, 0x1b, 0xea, 0xed, 0xd5, 0xa9, 0x72, 0x73, 0x7d,
0xf1, 0x41, 0x14, 0x15, 0xe5, 0x1c, 0x23, 0xe8, 0x8b, 0xd3, 0x8b, 0x7a,
0xe3, 0x12, 0xfd, 0x60, 0x98, 0x4a, 0x7b, 0x73, 0x56, 0x2c, 0x56, 0xba,
0xe3, 0x26, 0xb8, 0xf7, 0x27, 0x41, 0x69, 0x34, 0x3a, 0xad, 0x4c, 0x4d,
0x39, 0x39, 0x69, 0x75, 0x5b, 0x4f, 0x0f, 0x97, 0x57, 0xdd, 0xc7, 0x7e,
0xbd, 0xbe, 0x75, 0x34, 0xad, 0x4c, 0xce, 0xe6, 0x95, 0xc9, 0xe5, 0x6e,
0xf7, 0x56, 0x3b, 0xde, 0xae, 0x94, 0xba, 0xa5, 0x71, 0xbb, 0xd7, 0x10,
0x44, 0xb4, 0xdd, 0xae, 0x59, 0xa7, 0xbb, 0xbd, 0xf3, 0x6a, 0x63, 0x5e,
0xb9, 0xbf, 0x98, 0xc9, 0xc7, 0x2d, 0xbd, 0xb2, 0x63, 0x5e, 0xfc, 0x50,
0x38, 0x9b, 0x7d, 0xf3, 0xdc, 0xfc, 0x20, 0x6f, 0x6e, 0xdf, 0x8b, 0x96,
0x70, 0xf9, 0x70, 0xd1, 0x9c, 0x34, 0x07, 0xea, 0x6c, 0xaf, 0x53, 0x38,
0xb7, 0xbe, 0x69, 0x3f, 0x9b, 0x6d, 0xf9, 0x5e, 0x79, 0x6c, 0x64, 0xf6,
0xac, 0xd2, 0xfd, 0x75, 0xff, 0xe8, 0xf1, 0xe9, 0xc4, 0xa8, 0x98, 0x95,
0xa2, 0xd0, 0xba, 0xb8, 0x90, 0x37, 0xfb, 0xc5, 0x5a, 0x61, 0x72, 0xba,
0x7d, 0x76, 0x39, 0xb4, 0x3e, 0x14, 0x76, 0x8d, 0x1f, 0xf4, 0xeb, 0x2b,
0x45, 0xdf, 0xbd, 0xe8, 0x19, 0x7b, 0xa7, 0xdb, 0xc5, 0xe1, 0xf6, 0xee,
0x68, 0xd1, 0x10, 0xfa, 0xdd, 0xbd, 0xcc, 0xc8, 0xda, 0xad, 0xdf, 0xee,
0xb4, 0x4f, 0x6f, 0x86, 0xc5, 0xce, 0x7d, 0x46, 0x52, 0x6f, 0x9a, 0xfa,
0xf4, 0x7c, 0x3c, 0x98, 0xb7, 0x4e, 0x2a, 0x8f, 0x67, 0x8b, 0xdd, 0xc7,
0x9b, 0x81, 0xf8, 0xa1, 0x29, 0xb5, 0x2b, 0xdd, 0xd3, 0x71, 0xb7, 0x7e,
0xaf, 0xdf, 0x5d, 0xf4, 0x27, 0x5b, 0x3b, 0xfd, 0x5e, 0xe9, 0x32, 0x73,
0x74, 0x7d, 0x5d, 0x38, 0xda, 0xfc, 0xe6, 0x7a, 0x76, 0x33, 0x9e, 0xee,
0xea, 0xf3, 0xd3, 0xa7, 0x9b, 0x4d, 0x55, 0xbf, 0x35, 0x6f, 0x5b, 0x9d,
0xc5, 0xc9, 0xb4, 0x73, 0xb5, 0x79, 0x52, 0x98, 0x6c, 0x67, 0x3a, 0x3b,
0x8f, 0xf5, 0xf1, 0x87, 0x66, 0xed, 0xb6, 0xaa, 0x8f, 0xa7, 0x95, 0x9d,
0xc9, 0x60, 0x77, 0x7e, 0xdc, 0xba, 0x3c, 0x3e, 0xba, 0xa8, 0x0e, 0xba,
0x37, 0xb2, 0xd8, 0xdd, 0x36, 0x14, 0x71, 0xab, 0x3f, 0x2a, 0x5e, 0xb5,
0xcd, 0xdd, 0xa3, 0xe3, 0x6a, 0x6f, 0x77, 0x67, 0xbb, 0x51, 0xba, 0x69,
0x98, 0xfa, 0xdd, 0xf8, 0xf2, 0xe6, 0xae, 0x35, 0x28, 0x54, 0x9e, 0xb7,
0xc6, 0xa6, 0xd4, 0x95, 0x4a, 0x08, 0x55, 0x8f, 0xe7, 0x53, 0xa9, 0x79,
0x3d, 0x38, 0x16, 0xc7, 0xd5, 0x66, 0xef, 0xfe, 0x76, 0xd0, 0x19, 0x68,
0x13, 0xb1, 0x3e, 0x40, 0xc3, 0x0b, 0xad, 0x2b, 0x56, 0xc6, 0x77, 0x0f,
0x10, 0x88, 0xfd, 0x70, 0x93, 0xa9, 0x5c, 0x3d, 0xcd, 0xb6, 0x6e, 0xb7,
0xcc, 0x4a, 0xeb, 0x61, 0xd4, 0xd2, 0x9a, 0x6d, 0x13, 0xcd, 0xab, 0xa8,
0x7e, 0xd2, 0x39, 0x1f, 0x77, 0x17, 0x8b, 0xf3, 0xd3, 0x93, 0x3b, 0xb1,
0x79, 0xbc, 0xf3, 0x60, 0x9d, 0x15, 0x8a, 0x15, 0xa9, 0x72, 0xf4, 0xdc,
0x6a, 0xaa, 0xb3, 0xd9, 0x51, 0xa6, 0x64, 0x9d, 0xb5, 0xbe, 0xe9, 0xee,
0x1e, 0x4d, 0x8e, 0x8f, 0x87, 0x9d, 0xea, 0x75, 0xa6, 0x55, 0x7f, 0x16,
0x8f, 0xcf, 0x66, 0x37, 0xe2, 0x6e, 0xa9, 0x7d, 0x5f, 0xbf, 0x44, 0xf7,
0x67, 0xf2, 0x7c, 0xf6, 0x78, 0x75, 0x9c, 0x19, 0xcf, 0xba, 0xd5, 0xee,
0x73, 0xa7, 0xb9, 0x3d, 0x90, 0x2a, 0xc3, 0xdd, 0x7a, 0x47, 0xbc, 0x10,
0x1f, 0xba, 0x8f, 0x47, 0xf7, 0x37, 0x25, 0xb9, 0x76, 0x36, 0x5b, 0xd4,
0x6b, 0xa7, 0xdb, 0x5b, 0xa7, 0xda, 0xb0, 0x3d, 0xd0, 0x66, 0xd6, 0x43,
0x73, 0x7c, 0x24, 0x94, 0xfa, 0xdf, 0x5c, 0x3e, 0x9c, 0xb5, 0xe6, 0xd6,
0x5e, 0xeb, 0xe2, 0x69, 0xb6, 0x68, 0x5d, 0x55, 0x9f, 0x1e, 0xae, 0x06,
0x83, 0x87, 0x13, 0xad, 0x56, 0xbb, 0xac, 0x55, 0x1e, 0x26, 0x97, 0x1d,
0x59, 0xeb, 0x5f, 0xd7, 0xbe, 0x69, 0x6e, 0xf7, 0xbb, 0xf5, 0xce, 0x51,
0xb1, 0x72, 0xfe, 0x54, 0x2a, 0x7c, 0xd3, 0x2c, 0x0d, 0xf4, 0xd9, 0xe6,
0xe9, 0x76, 0x46, 0x59, 0xa0, 0xee, 0x76, 0x7f, 0x50, 0x1d, 0x9e, 0xf4,
0x8f, 0x74, 0xed, 0x0a, 0x29, 0x60, 0x19, 0xd5, 0xab, 0xc6, 0x70, 0x3e,
0xfb, 0xa0, 0xb5, 0xdb, 0xa7, 0x97, 0xd5, 0x89, 0x36, 0x78, 0xfa, 0x60,
0x4d, 0xa5, 0x0b, 0xb1, 0x3d, 0x7f, 0x9a, 0x9e, 0x97, 0x3a, 0x67, 0x5d,
0xe1, 0xec, 0x6e, 0xb1, 0x57, 0x78, 0x54, 0xab, 0xda, 0xce, 0xd5, 0x56,
0x6b, 0x47, 0x7e, 0xae, 0xf4, 0xa7, 0x3d, 0xb5, 0x2d, 0x14, 0x8f, 0x1e,
0xbe, 0x19, 0x21, 0xe3, 0x44, 0x9b, 0x9c, 0x4e, 0x8c, 0x4d, 0xbd, 0xb8,
0xf9, 0x6c, 0x28, 0xcf, 0xdb, 0x7b, 0xc6, 0x6d, 0x63, 0xbb, 0x03, 0x5d,
0x70, 0x7a, 0x3f, 0x28, 0x6d, 0x3d, 0x5e, 0x75, 0x9f, 0x6f, 0xf4, 0xcc,
0x7c, 0x78, 0xd3, 0xbc, 0x2a, 0xb4, 0xf4, 0x41, 0xeb, 0xee, 0x11, 0x06,
0xf4, 0xae, 0x65, 0x9e, 0xb4, 0x6a, 0x46, 0xfb, 0x87, 0xca, 0x4d, 0x63,
0x71, 0x57, 0x6a, 0xb6, 0x7a, 0x1f, 0x6e, 0xaf, 0x17, 0xe3, 0x6d, 0x34,
0x6f, 0x99, 0xa7, 0x23, 0xa1, 0xd9, 0x3e, 0xb9, 0xf9, 0xd0, 0x1a, 0x3c,
0x9c, 0x3f, 0xef, 0x9e, 0x55, 0xab, 0x77, 0x3b, 0x99, 0xa7, 0xa3, 0xc7,
0xab, 0xf3, 0x6f, 0xf6, 0xe0, 0x5b, 0x2f, 0xec, 0x35, 0xf6, 0xb4, 0x93,
0xc5, 0x56, 0x47, 0x36, 0x8f, 0xaf, 0xe7, 0xe8, 0x9b, 0x8e, 0xa0, 0x14,
0x8f, 0x17, 0x35, 0x18, 0x44, 0x5d, 0x18, 0x91, 0xf5, 0x93, 0x2e, 0x0c,
0xc8, 0xfa, 0x09, 0x0c, 0x4d, 0x52, 0x34, 0x81, 0xbf, 0x4e, 0x70, 0x05,
0x2d, 0xaa, 0xc3, 0xcf, 0x09, 0x85, 0x9d, 0x1f, 0xed, 0xd6, 0x0b, 0xd5,
0xdb, 0x71, 0xe5, 0xbc, 0xf8, 0x30, 0x69, 0xdd, 0x6d, 0x19, 0x83, 0xce,
0x37, 0x15, 0xfc, 0xa9, 0x2b, 0x8d, 0xfe, 0x7d, 0x6f, 0xd6, 0x9d, 0xd6,
0x6a, 0x7c, 0x1a, 0x5c, 0x73, 0xce, 0x40, 0x3a, 0x12, 0xac, 0x57, 0xba,
0x1e, 0x3c, 0x3b, 0x25, 0x76, 0x47, 0xab, 0x02, 0xad, 0x09, 0x0d, 0x6a,
0xb9, 0xcd, 0x1d, 0x5f, 0xcc, 0x47, 0x60, 0x63, 0xea, 0x60, 0x5a, 0xb4,
0x64, 0x51, 0x50, 0x72, 0x82, 0x22, 0x8f, 0x61, 0xd6, 0x9a, 0xca, 0x92,
0xa4, 0x24, 0x9d, 0x6c, 0xa2, 0x5d, 0x65, 0xce, 0x8d, 0x65, 0x36, 0x77,
0xf5, 0x45, 0x92, 0xa0, 0x25, 0x56, 0x62, 0x12, 0xe8, 0xe1, 0x28, 0x86,
0xe7, 0x3d, 0x4c, 0x93, 0xd0, 0x96, 0x89, 0x12, 0x9a, 0x78, 0xd9, 0xa4,
0x8b, 0x67, 0xdf, 0xe4, 0x72, 0x46, 0xf1, 0x4f, 0x48, 0xe5, 0xb6, 0x92,
0x4f, 0xe0, 0xf6, 0x9c, 0xc5, 0x65, 0x92, 0xcc, 0x28, 0xfe, 0x66, 0xa8,
0x2c, 0xe1, 0x66, 0x0a, 0x5f, 0x73, 0x34, 0xda, 0xe2, 0x04, 0xe9, 0x4e,
0x10, 0x41, 0x17, 0x1c, 0x04, 0x55, 0x53, 0xfc, 0x4d, 0xa3, 0x2b, 0xcd,
0xe0, 0x86, 0xb3, 0xf1, 0x48, 0x5e, 0x70, 0x5f, 0x17, 0x6c, 0xa4, 0xef,
0xc9, 0x2a, 0x91, 0xa3, 0x8b, 0x44, 0x4e, 0x50, 0x25, 0x2e, 0x65, 0xc7,
0x6c, 0x78, 0x65, 0x20, 0x01, 0xcf, 0x22, 0xca, 0xe9, 0xf2, 0x02, 0x29,
0x39, 0x12, 0xff, 0x94, 0x8b, 0x69, 0x86, 0xcb, 0x78, 0x0d, 0x8b, 0x48,
0xca, 0x83, 0x11, 0xa0, 0xa0, 0xc2, 0x5c, 0x48, 0x65, 0x60, 0x25, 0x36,
0x97, 0x39, 0xc6, 0x65, 0xce, 0xe6, 0x32, 0xc7, 0xb8, 0x94, 0xd5, 0x91,
0xac, 0xca, 0x16, 0xe2, 0x36, 0x4d, 0x5b, 0x5e, 0x57, 0x62, 0xc6, 0xbe,
0x4d, 0xfe, 0x1e, 0x3d, 0x8d, 0x0c, 0x61, 0x8a, 0xcc, 0xc4, 0xd4, 0x5d,
0x22, 0x3e, 0x7e, 0x47, 0x86, 0x36, 0x85, 0x22, 0x56, 0x1d, 0x13, 0xdf,
0x3b, 0xbc, 0xf8, 0xc0, 0x2c, 0x2d, 0x39, 0xa2, 0x4f, 0x9e, 0x90, 0x60,
0x9f, 0xcf, 0x74, 0x45, 0x13, 0x24, 0xb2, 0xb8, 0x49, 0x18, 0xf8, 0x87,
0x96, 0x94, 0x06, 0x1e, 0xc4, 0xab, 0x56, 0x99, 0x6c, 0xa8, 0x97, 0x76,
0xe3, 0xbd, 0x40, 0x69, 0xdb, 0xad, 0x73, 0x05, 0xca, 0x11, 0x5a, 0x64,
0xfd, 0x1d, 0x3d, 0x32, 0xa2, 0xd7, 0x7f, 0xb4, 0x14, 0x2f, 0xb8, 0xc2,
0xab, 0xbb, 0xcf, 0xb1, 0xfd, 0xac, 0x29, 0x70, 0x80, 0xf1, 0xa1, 0x66,
0x59, 0xda, 0x74, 0x99, 0xd0, 0xae, 0x4f, 0x28, 0x15, 0x29, 0xef, 0xa1,
0x9e, 0xc2, 0x24, 0xc3, 0xcc, 0x21, 0x92, 0x78, 0xc9, 0x72, 0x9f, 0xeb,
0x06, 0x31, 0xf2, 0xb7, 0x31, 0x6a, 0x77, 0x4e, 0x22, 0xde, 0x09, 0xa7,
0x61, 0x96, 0x5c, 0x4e, 0x96, 0x75, 0x00, 0xd1, 0x75, 0x58, 0xca, 0x0f,
0x61, 0x8a, 0x07, 0x05, 0xbc, 0x2e, 0x75, 0x93, 0x4a, 0xa2, 0x21, 0xeb,
0x96, 0x93, 0x36, 0x1a, 0xcd, 0x54, 0x11, 0x8b, 0xc8, 0x89, 0x06, 0x4c,
0x61, 0xa8, 0x21, 0x2b, 0xe8, 0x92, 0x19, 0x69, 0x8a, 0x0d, 0xb1, 0x2c,
0x87, 0x7b, 0x30, 0xcb, 0x51, 0x55, 0xa5, 0x3d, 0x6c, 0x3d, 0x0a, 0x06,
0xb7, 0x98, 0x2a, 0xc7, 0x96, 0xa5, 0xef, 0xfb, 0x4a, 0xd9, 0x72, 0xe6,
0x90, 0x93, 0x34, 0x71, 0x86, 0x69, 0xe4, 0x29, 0xf9, 0x3a, 0xa5, 0x98,
0xe2, 0x49, 0x3d, 0xef, 0xcd, 0xe7, 0x90, 0x92, 0x3c, 0x4e, 0x76, 0x01,
0x1a, 0x3f, 0x02, 0x3e, 0xf8, 0x50, 0xed, 0x14, 0xd6, 0x14, 0xb2, 0xae,
0x60, 0x88, 0x91, 0xa0, 0x98, 0x28, 0x04, 0xa0, 0x0a, 0x53, 0x5c, 0x49,
0x82, 0x74, 0x0f, 0xba, 0xcb, 0xc6, 0x18, 0x59, 0x8c, 0x87, 0xea, 0xd3,
0x89, 0x64, 0x4b, 0x98, 0xce, 0x0b, 0xba, 0x8e, 0x54, 0xa9, 0x36, 0x91,
0x15, 0x29, 0x45, 0x48, 0xa5, 0x03, 0x02, 0xe9, 0x82, 0x35, 0x59, 0x4b,
0x1e, 0x8c, 0x90, 0x97, 0x25, 0xcc, 0x0d, 0x1d, 0xf5, 0x39, 0x5c, 0xc2,
0x07, 0x20, 0x1c, 0x81, 0xf1, 0x6a, 0x34, 0x58, 0xe9, 0x88, 0x13, 0x89,
0xc9, 0xd6, 0x58, 0x57, 0x82, 0x32, 0x23, 0x40, 0x85, 0x57, 0x0b, 0x8c,
0xc9, 0x05, 0xe5, 0x1d, 0xce, 0xc0, 0x6c, 0xd5, 0x25, 0x12, 0x53, 0x00,
0x9f, 0xc8, 0xb4, 0x28, 0x2f, 0xab, 0x2a, 0x32, 0x8e, 0xfb, 0xed, 0x33,
0xc0, 0xde, 0xa0, 0xc6, 0xb4, 0xf1, 0x5a, 0xd6, 0x28, 0xc9, 0x20, 0x73,
0xd3, 0x7b, 0x49, 0x36, 0xd6, 0xe3, 0x8d, 0xa0, 0xf8, 0x59, 0x6b, 0xdf,
0x1f, 0xc9, 0xc6, 0xab, 0x39, 0x23, 0x04, 0xc3, 0x8c, 0x61, 0xc3, 0x5d,
0x97, 0x33, 0x8c, 0x13, 0x64, 0x0d, 0x0f, 0xc4, 0x37, 0xf0, 0x86, 0x49,
0x86, 0x4d, 0xd8, 0x10, 0xe2, 0x59, 0xa3, 0x16, 0xe8, 0xc1, 0x21, 0xf0,
0x3e, 0xb6, 0x78, 0x8e, 0x3b, 0x37, 0x90, 0x69, 0x72, 0x35, 0xcb, 0x50,
0x72, 0x3d, 0x0e, 0x22, 0x1b, 0xc8, 0xaf, 0x3e, 0xa2, 0x2c, 0x2d, 0xb8,
0x25, 0x05, 0xe0, 0xa3, 0x34, 0x56, 0xd0, 0x9b, 0xc8, 0x23, 0x8b, 0x15,
0x1b, 0x48, 0xd2, 0xde, 0x60, 0xa0, 0x86, 0x40, 0x39, 0x0b, 0x38, 0xad,
0x09, 0x78, 0x9e, 0x73, 0xcd, 0xb4, 0xce, 0x0d, 0x4d, 0x04, 0xc6, 0x2e,
0xd0, 0xc3, 0x0c, 0x99, 0x56, 0x2a, 0xed, 0x9b, 0xfa, 0xe5, 0x11, 0x97,
0x62, 0x5e, 0x2a, 0x0f, 0x22, 0x4b, 0x4f, 0x3d, 0x0b, 0xe4, 0xe6, 0x0e,
0x0f, 0xb9, 0x6d, 0x1b, 0xd0, 0x05, 0x75, 0x20, 0x4d, 0x00, 0x9a, 0x99,
0xdc, 0x67, 0x87, 0xd8, 0x4f, 0xa7, 0x39, 0x41, 0x41, 0x06, 0x28, 0xa9,
0x7e, 0x71, 0xd1, 0xb9, 0xf8, 0x91, 0xcf, 0xf8, 0xa1, 0x32, 0xfc, 0xcf,
0x65, 0xce, 0x2d, 0x04, 0x1d, 0xe9, 0x9a, 0x6a, 0xa2, 0x3e, 0x68, 0x94,
0xb2, 0xed, 0x7e, 0x90, 0x62, 0xda, 0xd1, 0xa0, 0xfb, 0x21, 0x0e, 0x16,
0xd0, 0x46, 0x80, 0x39, 0x39, 0x87, 0xd1, 0x98, 0x22, 0x23, 0xfc, 0x11,
0x0f, 0xed, 0x20, 0x81, 0x97, 0x15, 0xf1, 0x46, 0xd8, 0xa7, 0x53, 0x82,
0x7e, 0x51, 0x19, 0xab, 0xd0, 0xa9, 0x2a, 0xcc, 0x34, 0x83, 0xf6, 0x19,
0xfe, 0x65, 0xab, 0xcf, 0xdf, 0xa4, 0x2d, 0x95, 0xa6, 0x12, 0xe5, 0x61,
0x89, 0x91, 0x38, 0x81, 0x7d, 0x0d, 0x50, 0x61, 0x4c, 0x07, 0x50, 0x7c,
0xd7, 0xf4, 0xb0, 0x05, 0x4c, 0x8f, 0xc0, 0x27, 0xb3, 0xf6, 0x1a, 0xec,
0xa7, 0xbf, 0x25, 0x07, 0x8a, 0xf5, 0x7d, 0x8a, 0xfa, 0xbd, 0x2c, 0xa7,
0xc7, 0x30, 0x04, 0x40, 0x29, 0xfe, 0xfc, 0xb2, 0x0f, 0x20, 0x7c, 0x01,
0xcf, 0x4e, 0x7c, 0x34, 0xa0, 0x89, 0x89, 0xd9, 0xc4, 0x09, 0x48, 0x58,
0x67, 0xc1, 0xf1, 0x08, 0xe2, 0x8a, 0x8a, 0x2c, 0xde, 0x73, 0x87, 0x8e,
0x3a, 0x53, 0x28, 0x68, 0x57, 0x9e, 0x6e, 0xca, 0x93, 0x5d, 0x96, 0xce,
0x28, 0xc5, 0xe7, 0xf9, 0x34, 0xd8, 0xd6, 0x21, 0x04, 0xf4, 0x69, 0xb0,
0x7a, 0x6b, 0x66, 0xa8, 0x5e, 0xa6, 0x58, 0x9f, 0x2c, 0xeb, 0x64, 0x36,
0xd1, 0xe6, 0xb1, 0xe3, 0xbc, 0x34, 0x94, 0x18, 0xb0, 0x97, 0xa0, 0x73,
0x5b, 0x9b, 0x63, 0x05, 0xa9, 0x63, 0x98, 0xd4, 0x0e, 0xb8, 0x92, 0xcd,
0x68, 0xa8, 0xdf, 0xa8, 0x9b, 0x75, 0x71, 0x02, 0xc4, 0xa0, 0xda, 0x2f,
0xf7, 0x67, 0x44, 0x6e, 0xda, 0x68, 0x08, 0x52, 0x11, 0x4c, 0xeb, 0xc4,
0x86, 0x2e, 0x30, 0x2d, 0x15, 0x23, 0xdb, 0xe6, 0x58, 0xcb, 0x18, 0xcd,
0x9c, 0x0d, 0x4d, 0xcb, 0x80, 0xe0, 0x26, 0x05, 0x9b, 0x40, 0x51, 0x74,
0xfc, 0xca, 0x7b, 0x89, 0x51, 0x76, 0xc0, 0x5b, 0xbf, 0x84, 0xe6, 0xad,
0x64, 0xfa, 0xa3, 0x71, 0x06, 0xb6, 0x10, 0x93, 0x29, 0x90, 0x8a, 0x11,
0x90, 0x39, 0x4a, 0xa8, 0x97, 0x7f, 0xdf, 0x00, 0x24, 0x71, 0x54, 0x96,
0xf3, 0x08, 0xfd, 0x63, 0xf1, 0xe7, 0xac, 0xc7, 0x20, 0x96, 0x8e, 0xcc,
0x4e, 0xef, 0x5d, 0x86, 0x26, 0x69, 0x1d, 0xa4, 0xa7, 0x32, 0xbf, 0xb2,
0x7b, 0xe2, 0x2c, 0x1c, 0x83, 0xd2, 0x30, 0x2b, 0x20, 0x25, 0x09, 0xbe,
0x42, 0xe0, 0xe0, 0xd1, 0x01, 0xb2, 0x90, 0xfa, 0xae, 0xfc, 0x53, 0x3e,
0xf5, 0xe3, 0x2f, 0xf9, 0x9f, 0x33, 0xe9, 0xf4, 0x77, 0x5f, 0x14, 0xf2,
0x68, 0x81, 0xc4, 0x94, 0x4d, 0x2b, 0xfd, 0xe3, 0xe6, 0xcf, 0x21, 0x4c,
0x5c, 0x41, 0x50, 0xf3, 0x5f, 0xa7, 0x7f, 0xca, 0x13, 0xd4, 0x95, 0x78,
0x20, 0x10, 0x8e, 0x0f, 0xb5, 0x11, 0xc1, 0xc6, 0xa3, 0x8b, 0x6c, 0x52,
0x8c, 0x60, 0x1d, 0x27, 0x45, 0x0c, 0x32, 0x0c, 0x64, 0x4b, 0xfd, 0x2d,
0xb7, 0x9b, 0x66, 0x6d, 0x92, 0x2f, 0xff, 0x30, 0xda, 0x0d, 0xcc, 0x2a,
0x5e, 0x35, 0x84, 0xe4, 0x7e, 0x89, 0x64, 0x09, 0xab, 0x62, 0x25, 0x47,
0x00, 0x43, 0xf4, 0xcf, 0xe3, 0xcd, 0x70, 0x3e, 0x4d, 0x70, 0xe8, 0x2f,
0x3e, 0x62, 0x5e, 0xf4, 0x61, 0xdc, 0xe9, 0x68, 0xcc, 0x30, 0xc8, 0xaf,
0x31, 0x1f, 0xcb, 0xb2, 0xfb, 0x98, 0xe1, 0xc0, 0x0d, 0xc1, 0xdf, 0x80,
0xb5, 0x54, 0x04, 0xd7, 0x80, 0x69, 0x63, 0x05, 0x9e, 0xfb, 0xed, 0x37,
0x8f, 0x59, 0xc7, 0xf8, 0xaa, 0xa0, 0x84, 0x1e, 0x32, 0x84, 0x48, 0xc6,
0x66, 0xc4, 0xdf, 0x38, 0x15, 0x6e, 0x09, 0xae, 0xfb, 0xc3, 0xdf, 0x4f,
0xcb, 0x38, 0xca, 0x6c, 0xa6, 0x9d, 0xe6, 0xd6, 0xc9, 0x41, 0x04, 0x82,
0x83, 0x3e, 0x44, 0x1e, 0x76, 0xd0, 0x15, 0xb7, 0xc4, 0xb3, 0x17, 0xa4,
0x87, 0xb1, 0x51, 0x1b, 0xcf, 0x40, 0xf8, 0x40, 0xcc, 0x49, 0x02, 0x9b,
0x0b, 0x4d, 0x5b, 0xb6, 0x14, 0x94, 0xe4, 0x47, 0x2f, 0x9a, 0x8d, 0x02,
0x70, 0x20, 0xb2, 0xf9, 0x03, 0x5b, 0x02, 0x79, 0x13, 0x51, 0xaf, 0x8e,
0x23, 0x6d, 0xd2, 0xb4, 0xb9, 0x88, 0x80, 0x09, 0x4f, 0xb9, 0x47, 0xda,
0x5c, 0xc5, 0xdf, 0xc4, 0x48, 0xa8, 0x2a, 0x56, 0x35, 0xb6, 0x21, 0x31,
0x9c, 0x1c, 0x49, 0x56, 0x6d, 0xa4, 0xf3, 0xa6, 0x21, 0xb2, 0x6e, 0xcd,
0xf0, 0xdf, 0xd9, 0xb5, 0x87, 0x96, 0x31, 0xf3, 0xad, 0x6a, 0x5f, 0x96,
0xb0, 0x71, 0x4e, 0x35, 0xba, 0x06, 0x17, 0x3c, 0xed, 0x3d, 0x1e, 0x5a,
0xc7, 0x0b, 0xfe, 0x3c, 0xcb, 0x15, 0x63, 0xed, 0xe1, 0xed, 0x43, 0xdf,
0xf8, 0xb1, 0xfb, 0x34, 0x0c, 0x4a, 0x32, 0xca, 0x91, 0xb0, 0xfe, 0x25,
0xca, 0x81, 0x3c, 0x1d, 0x73, 0x20, 0xe6, 0x21, 0xbf, 0x91, 0x21, 0x72,
0x6e, 0xf0, 0x1c, 0x21, 0x76, 0xc8, 0x4f, 0x85, 0x05, 0x3b, 0x7b, 0xb0,
0x59, 0x2c, 0x7e, 0xb9, 0xcf, 0xc1, 0x6f, 0x96, 0x76, 0xa2, 0x05, 0x76,
0x9e, 0x56, 0x98, 0x59, 0xda, 0xbe, 0x93, 0xd2, 0xa6, 0xa9, 0x6c, 0x9e,
0x2b, 0x7c, 0xbb, 0x91, 0x40, 0x45, 0x60, 0xfa, 0x4a, 0x43, 0x53, 0x20,
0x4d, 0x81, 0x8f, 0x00, 0xa4, 0x70, 0x5a, 0xdd, 0xd5, 0x94, 0xc7, 0x02,
0xf1, 0xce, 0xfc, 0x32, 0xeb, 0x9b, 0x29, 0x81, 0x99, 0x09, 0x29, 0x3e,
0x93, 0xc1, 0xe8, 0xe9, 0x90, 0x33, 0x17, 0x08, 0x13, 0x4b, 0xc8, 0x2a,
0x72, 0x80, 0x2c, 0xa6, 0xe3, 0x23, 0x4c, 0x49, 0x84, 0x49, 0xcb, 0x66,
0x8d, 0xe6, 0x90, 0x97, 0x0c, 0x37, 0x22, 0x69, 0x9e, 0xe5, 0x9a, 0x23,
0xe6, 0x28, 0x5d, 0x95, 0xde, 0xc4, 0x1b, 0xa1, 0x90, 0x0e, 0x4e, 0x45,
0x8c, 0xb3, 0xb0, 0xa3, 0x27, 0xe0, 0xfe, 0x95, 0xe2, 0x01, 0xde, 0xd5,
0xf8, 0xb6, 0xa6, 0x29, 0x8a, 0xa0, 0x9b, 0xe8, 0xa0, 0x40, 0x7e, 0xf2,
0xfb, 0x11, 0x78, 0x09, 0xc2, 0x2e, 0xf8, 0x24, 0x53, 0x45, 0x38, 0x2f,
0xe4, 0x72, 0xef, 0x10, 0x18, 0x6a, 0xd2, 0x93, 0x87, 0x8a, 0x59, 0x7d,
0xaa, 0xd9, 0x8e, 0x26, 0xb5, 0xe1, 0x39, 0x56, 0xb2, 0x91, 0x76, 0xe6,
0x52, 0x1c, 0x3f, 0xf8, 0xf1, 0x0d, 0x34, 0x85, 0xf3, 0x04, 0x4c, 0x5b,
0x4a, 0x68, 0x8d, 0xe6, 0xfc, 0x76, 0x7b, 0x05, 0xaf, 0xee, 0xcc, 0xc9,
0x3a, 0xdd, 0x12, 0xd1, 0x31, 0x94, 0x48, 0x10, 0x8c, 0x96, 0x46, 0x75,
0xc0, 0x05, 0x5d, 0x52, 0xda, 0xfa, 0x8f, 0xc4, 0x4b, 0xd8, 0x01, 0x64,
0x2c, 0x21, 0x61, 0xb4, 0xd2, 0x2c, 0x61, 0xb1, 0x0e, 0x05, 0x3f, 0x68,
0x52, 0x64, 0x37, 0x60, 0x12, 0x79, 0x11, 0x0b, 0x03, 0x10, 0xde, 0x20,
0x8d, 0xdb, 0x4a, 0x13, 0xfa, 0x5e, 0xd5, 0x06, 0xa1, 0x7f, 0x2c, 0xfd,
0x9c, 0x0e, 0x12, 0x25, 0x11, 0x70, 0x13, 0x59, 0x04, 0x96, 0x39, 0x81,
0x7f, 0x56, 0xff, 0xb3, 0xf9, 0x3f, 0xe9, 0xa0, 0xa9, 0x2f, 0xe0, 0x6f,
0xe9, 0x2f, 0x1c, 0x32, 0x78, 0x56, 0xda, 0xff, 0xbf, 0xbb, 0xdf, 0xad,
0xbb, 0x83, 0xfe, 0x98, 0xa4, 0x7f, 0xdf, 0xe6, 0x90, 0x29, 0x09, 0x3f,
0x10, 0x29, 0x8b, 0xb4, 0x20, 0x92, 0x73, 0x75, 0x2c, 0x28, 0x8c, 0x94,
0xcc, 0x80, 0xec, 0xac, 0x77, 0x5d, 0x59, 0x62, 0x03, 0xde, 0xdc, 0xb6,
0x2b, 0x84, 0xdb, 0x0d, 0x94, 0x40, 0xb4, 0x37, 0x81, 0x48, 0xf7, 0x9c,
0x66, 0xd5, 0x29, 0x14, 0x0d, 0x74, 0xa3, 0x3a, 0x93, 0x41, 0x86, 0xa3,
0xf2, 0x03, 0x6e, 0x33, 0xed, 0xc3, 0xb6, 0x83, 0x2e, 0x86, 0x11, 0x24,
0x46, 0x46, 0x62, 0x14, 0x82, 0x1b, 0x76, 0xc7, 0x36, 0x96, 0x0e, 0x12,
0x75, 0xfb, 0xfb, 0x6f, 0xb3, 0xbd, 0x97, 0x70, 0xc6, 0x06, 0x29, 0x38,
0x75, 0xfc, 0x26, 0x6b, 0x63, 0x34, 0xfc, 0x50, 0xac, 0x30, 0xca, 0xde,
0x8e, 0x20, 0xd8, 0xb6, 0x9c, 0x49, 0x3e, 0x84, 0x95, 0x2c, 0x9b, 0x46,
0x47, 0x36, 0x25, 0xc5, 0x76, 0x24, 0xfe, 0x21, 0x8a, 0x5d, 0x12, 0x82,
0x12, 0xe1, 0xfe, 0x43, 0x01, 0x28, 0x89, 0xf2, 0x70, 0xda, 0x1a, 0xe4,
0x62, 0xbd, 0x10, 0xec, 0x25, 0x8a, 0x16, 0x39, 0x71, 0xc1, 0xf2, 0xc3,
0x31, 0x82, 0x30, 0x52, 0xa2, 0x0c, 0x5b, 0x44, 0xfa, 0xf3, 0x9f, 0xe8,
0xe2, 0x89, 0x1f, 0xa1, 0xda, 0x3a, 0xc1, 0x47, 0x01, 0x5f, 0xa3, 0x2e,
0xb6, 0xc0, 0x7b, 0x0f, 0x8d, 0x79, 0xd6, 0x8b, 0xff, 0x48, 0x75, 0x05,
0xad, 0x17, 0x2f, 0x88, 0xdf, 0x3c, 0x27, 0xda, 0x44, 0xfc, 0x60, 0x76,
0x69, 0xa4, 0x9f, 0x62, 0x75, 0xb6, 0xca, 0x43, 0x88, 0x89, 0xe7, 0x46,
0x6f, 0x9e, 0xe0, 0x9f, 0xe5, 0xac, 0xfe, 0x9f, 0x05, 0xfe, 0x24, 0xc5,
0xc6, 0xcd, 0x02, 0xe6, 0x44, 0x9b, 0xd7, 0xdc, 0xb6, 0x52, 0x88, 0xce,
0x03, 0x59, 0x58, 0xc8, 0x93, 0x4d, 0xd8, 0x8f, 0xe1, 0x3d, 0x95, 0x47,
0x0a, 0xbf, 0x4e, 0x52, 0x8c, 0xa0, 0xe2, 0xe3, 0x5c, 0xb0, 0xa2, 0xee,
0x6b, 0xb0, 0x6d, 0x10, 0x90, 0xc2, 0xad, 0xf9, 0x2e, 0xb6, 0xa6, 0xec,
0xd6, 0xd8, 0x0f, 0xac, 0x3d, 0x17, 0x28, 0xa6, 0xc9, 0x33, 0x38, 0xb0,
0x12, 0x6e, 0xd3, 0xad, 0xfa, 0x2e, 0xb6, 0x6a, 0x75, 0xab, 0x18, 0x2a,
0xd4, 0xac, 0x42, 0x1b, 0x44, 0x79, 0x30, 0x18, 0x00, 0x1d, 0x40, 0x4e,
0x37, 0x1e, 0x1a, 0x1f, 0xc5, 0xf1, 0x00, 0xdf, 0x50, 0xe0, 0xb0, 0x40,
0xae, 0xea, 0xfd, 0xc9, 0x45, 0x9f, 0xad, 0xc4, 0x20, 0x84, 0x12, 0x65,
0x1b, 0x24, 0x5f, 0xb5, 0x02, 0x9c, 0x89, 0x81, 0xbf, 0x80, 0xa9, 0x0d,
0x7d, 0xb1, 0x02, 0x9e, 0x0a, 0x02, 0x7f, 0xbb, 0xd0, 0x3e, 0xd3, 0x67,
0x36, 0xe5, 0x0f, 0x3d, 0x5c, 0x2a, 0xee, 0x7a, 0x28, 0x10, 0xf1, 0xba,
0xd9, 0xb2, 0x04, 0x18, 0xbe, 0xae, 0xf4, 0xb9, 0x04, 0x17, 0x2f, 0x6c,
0x9b, 0x24, 0xe1, 0xc7, 0x1d, 0x7a, 0x65, 0xd2, 0x46, 0x23, 0x13, 0x59,
0xd7, 0xb8, 0x22, 0x04, 0x4e, 0xf3, 0x81, 0x51, 0xf0, 0xc7, 0xa4, 0x26,
0x4e, 0x4f, 0x9a, 0x3a, 0xd5, 0xe0, 0x66, 0x09, 0x1c, 0x76, 0x8e, 0xf6,
0x22, 0xae, 0xae, 0x5c, 0xdb, 0x39, 0x20, 0x1d, 0x80, 0x33, 0xfc, 0x6e,
0xd9, 0xb7, 0x5c, 0x8a, 0xf6, 0x0a, 0x65, 0x3c, 0xed, 0xad, 0xbd, 0x01,
0x0c, 0xe8, 0x03, 0x5f, 0x11, 0x46, 0x20, 0xfd, 0xc2, 0x38, 0x87, 0x89,
0xfe, 0x2f, 0x9d, 0x63, 0x83, 0xaa, 0x77, 0x3f, 0x2f, 0xeb, 0x7a, 0x2c,
0x37, 0xf1, 0x7f, 0x86, 0x04, 0xba, 0x44, 0xcb, 0x92, 0x5d, 0x9f, 0x2c,
0x87, 0xef, 0xd3, 0x45, 0x44, 0xb0, 0x00, 0xb6, 0xd6, 0x54, 0x02, 0xf0,
0xf4, 0xe8, 0x53, 0x2a, 0x45, 0xc8, 0x73, 0x74, 0x8f, 0x25, 0xfd, 0x1d,
0xcf, 0x97, 0x89, 0xbd, 0x65, 0xe0, 0x57, 0x86, 0x6c, 0x79, 0x81, 0xc9,
0x9f, 0x69, 0x73, 0x64, 0xd4, 0xe0, 0x1e, 0x45, 0x2a, 0x64, 0x55, 0xf4,
0x14, 0xed, 0x92, 0xb6, 0xf1, 0x64, 0xe3, 0x6f, 0x9d, 0xa2, 0xe4, 0xb1,
0xa6, 0x6a, 0xf4, 0xe8, 0x30, 0xdb, 0xd3, 0xf2, 0xb5, 0x14, 0x66, 0xd8,
0x67, 0xe8, 0x84, 0x46, 0x18, 0x26, 0xd1, 0x04, 0xe6, 0x8f, 0xa1, 0x99,
0x2e, 0xd2, 0x2b, 0xc3, 0x5c, 0x06, 0x48, 0x1b, 0x5d, 0x11, 0x6a, 0x3a,
0xc0, 0x4b, 0x43, 0x41, 0x1b, 0x2a, 0xb1, 0xc1, 0x38, 0x42, 0x32, 0x03,
0x05, 0x15, 0xcf, 0x96, 0x8a, 0x8a, 0xf2, 0x78, 0x6b, 0x00, 0x54, 0x7c,
0x44, 0xcf, 0xa2, 0x39, 0x6a, 0x75, 0x01, 0x4c, 0x18, 0x34, 0xb0, 0x37,
0xad, 0x0b, 0x63, 0x72, 0x4a, 0x38, 0x08, 0x11, 0x35, 0x7d, 0x32, 0xb6,
0xb3, 0x24, 0x31, 0x15, 0x9e, 0x90, 0x83, 0x7b, 0xec, 0x04, 0x7e, 0x2d,
0xb3, 0xaf, 0x1a, 0x02, 0x6c, 0x26, 0xfb, 0x0c, 0xdf, 0xbe, 0x5e, 0xf4,
0x76, 0xe3, 0xc7, 0x38, 0x24, 0xb7, 0xb6, 0xd6, 0x69, 0x41, 0x8e, 0xe2,
0x38, 0xc7, 0x01, 0xc9, 0x2f, 0xb8, 0x15, 0xcb, 0x87, 0x61, 0xde, 0x61,
0x64, 0xb9, 0x9b, 0xb8, 0xce, 0x65, 0xae, 0xcf, 0x30, 0x21, 0x67, 0x2b,
0x97, 0xe7, 0xbe, 0xfa, 0xca, 0xd5, 0x09, 0x6b, 0xd7, 0xfe, 0x8d, 0xf9,
0xb3, 0x9f, 0xf9, 0xe5, 0xe3, 0x88, 0x20, 0xae, 0x3f, 0xaa, 0x49, 0x7d,
0xe4, 0xb0, 0xc6, 0x47, 0xc9, 0x0e, 0x1d, 0x3d, 0xfc, 0x15, 0xe3, 0x9e,
0xb4, 0x95, 0xe4, 0xf4, 0x01, 0x51, 0x2b, 0x85, 0x16, 0xed, 0x7d, 0x92,
0xbf, 0x21, 0x23, 0x4a, 0xda, 0x5e, 0x73, 0xd4, 0x63, 0xa9, 0x93, 0xfa,
0xb6, 0xcf, 0x56, 0x88, 0xe8, 0x54, 0xbb, 0xd9, 0xe5, 0xbf, 0x25, 0x33,
0x4c, 0x38, 0x88, 0x77, 0xa8, 0x2b, 0xf9, 0x26, 0x1b, 0x49, 0x6b, 0xe8,
0xf0, 0x9f, 0xe0, 0x39, 0x6d, 0x99, 0xb3, 0x84, 0xfb, 0xa0, 0xef, 0x7c,
0xbd, 0xeb, 0x84, 0xc3, 0xe5, 0x67, 0xb0, 0x3c, 0x4c, 0xd1, 0x5c, 0xbf,
0xb3, 0xc0, 0xb1, 0xd0, 0xd4, 0x7c, 0x7b, 0xbe, 0x8b, 0x12, 0x4d, 0x90,
0xf3, 0x52, 0xc0, 0x65, 0x90, 0x46, 0x6d, 0x63, 0x09, 0x9e, 0x5d, 0x4a,
0x91, 0xfd, 0x53, 0x00, 0x2a, 0xee, 0xc3, 0xd7, 0x01, 0x20, 0xc0, 0x77,
0x26, 0x13, 0x91, 0xd8, 0x26, 0x64, 0x6c, 0x6a, 0x3f, 0xca, 0x3f, 0xef,
0x47, 0x43, 0xd4, 0x95, 0xf0, 0xea, 0x13, 0x97, 0x33, 0x37, 0x7d, 0x68,
0x1f, 0x54, 0x0f, 0x8d, 0x02, 0x86, 0x0d, 0x2d, 0x44, 0x06, 0x5b, 0x84,
0x06, 0xf6, 0x4d, 0xec, 0x11, 0x87, 0x5d, 0x49, 0xed, 0xd4, 0xa6, 0x1c,
0x9a, 0xcf, 0x02, 0xb4, 0xc3, 0x04, 0x57, 0xec, 0x2d, 0x52, 0xc2, 0x91,
0x36, 0xb3, 0xda, 0x42, 0x82, 0x59, 0xc3, 0x8f, 0x6b, 0x1d, 0x9c, 0xc2,
0x28, 0xe4, 0xf0, 0xd3, 0x2b, 0x4f, 0x1a, 0x99, 0x73, 0xd9, 0x02, 0x05,
0x00, 0x5c, 0x84, 0x3f, 0x02, 0xb7, 0x0f, 0xc7, 0xeb, 0xe1, 0x6c, 0x73,
0x39, 0xaa, 0x8a, 0x1c, 0x46, 0x5a, 0x52, 0xa5, 0xc4, 0xd5, 0xdd, 0x99,
0xf1, 0x35, 0x9a, 0x1a, 0x57, 0x27, 0xc6, 0x36, 0x15, 0x8b, 0xa1, 0xeb,
0xb1, 0x55, 0x66, 0x2c, 0x0f, 0x8b, 0x30, 0xe3, 0xee, 0xb0, 0x27, 0x3e,
0x39, 0xe1, 0xb1, 0x62, 0x1b, 0x87, 0x7a, 0x94, 0x04, 0xbe, 0x82, 0x85,
0xa9, 0xff, 0x5c, 0x53, 0x80, 0x5b, 0xdb, 0xb1, 0x3d, 0xa7, 0xc7, 0x56,
0x8d, 0xe5, 0x51, 0x5c, 0x95, 0x2c, 0x6a, 0x7f, 0xad, 0xae, 0xad, 0x89,
0x6c, 0x7a, 0x4f, 0x8b, 0x7b, 0x66, 0x1a, 0x47, 0xe5, 0xfe, 0x5d, 0xb8,
0xe0, 0x7e, 0xd6, 0x46, 0x61, 0x83, 0x6c, 0x9e, 0x85, 0x0e, 0xb4, 0x51,
0x6a, 0x50, 0xcd, 0x5a, 0x0f, 0x1e, 0xca, 0xf2, 0x4d, 0xca, 0x76, 0xa1,
0x77, 0x62, 0x2e, 0xd2, 0x89, 0x39, 0x3c, 0x2d, 0x3b, 0xd0, 0x59, 0x12,
0xb0, 0x26, 0xd8, 0x21, 0xa7, 0xcc, 0x90, 0xaf, 0xd0, 0xa9, 0xb8, 0xb0,
0x38, 0x98, 0xe2, 0xfb, 0x6e, 0x60, 0xff, 0x09, 0x41, 0x4a, 0xfc, 0xe6,
0x75, 0xf8, 0xec, 0x5e, 0xcc, 0x19, 0x35, 0x9c, 0x4c, 0xad, 0x0d, 0x59,
0x3f, 0x87, 0x6d, 0xc7, 0xb5, 0x04, 0x5a, 0xfb, 0xaa, 0x6b, 0x10, 0xf1,
0x17, 0x21, 0xc2, 0x90, 0xdc, 0xbb, 0x5d, 0x8d, 0x08, 0xdb, 0xc1, 0xeb,
0x8c, 0x38, 0xd6, 0x94, 0xdf, 0xc9, 0xa0, 0x13, 0x9b, 0x75, 0xb4, 0x50,
0xef, 0x67, 0xe2, 0xef, 0x65, 0xe8, 0x7f, 0x9a, 0xb9, 0x27, 0x33, 0x7a,
0xc7, 0xf4, 0x03, 0x05, 0xc9, 0x9c, 0x66, 0xdc, 0x3c, 0xe4, 0xee, 0x23,
0x38, 0xe7, 0xab, 0xff, 0x9c, 0x2b, 0x30, 0x64, 0x3c, 0xba, 0x6d, 0xbc,
0xd7, 0xd1, 0x7b, 0x76, 0xf7, 0x85, 0xd1, 0x5d, 0x7a, 0xd0, 0xfe, 0xa8,
0x7e, 0x56, 0xef, 0xd7, 0xdf, 0x76, 0xd4, 0x3e, 0x42, 0x83, 0x60, 0x44,
0xb5, 0xa1, 0x13, 0xf3, 0xff, 0xc9, 0x0e, 0xa7, 0x50, 0x10, 0xc1, 0x3e,
0x0c, 0x92, 0xbf, 0x82, 0x31, 0xb0, 0xda, 0x1f, 0x1d, 0x52, 0x7f, 0x14,
0xb3, 0x36, 0x39, 0xed, 0x75, 0x7e, 0xc0, 0x06, 0x0f, 0x4b, 0xfe, 0x48,
0xd7, 0xb3, 0xd6, 0xad, 0xaa, 0xb0, 0x6e, 0x98, 0x4d, 0xfb, 0x5b, 0x5d,
0xc3, 0xbc, 0xbc, 0x68, 0x6b, 0x98, 0x1a, 0xe9, 0x91, 0x24, 0xc8, 0xc4,
0x2c, 0x9a, 0x75, 0x7a, 0xfd, 0x02, 0x47, 0xfa, 0xdf, 0xc1, 0xf5, 0x97,
0x43, 0x9e, 0x1c, 0xd4, 0xa5, 0x79, 0xb5, 0x25, 0x36, 0xa2, 0xce, 0x14,
0xb6, 0x0c, 0x70, 0x3b, 0x07, 0xf8, 0x30, 0x2c, 0xbb, 0x73, 0x42, 0xea,
0x49, 0xec, 0x13, 0xa9, 0xc9, 0x90, 0x00, 0x66, 0x7f, 0xf5, 0xd9, 0x74,
0xf2, 0x52, 0x3c, 0xe7, 0x1a, 0x32, 0x1d, 0x0b, 0x59, 0xf2, 0x4a, 0xbd,
0x2c, 0x90, 0x80, 0x42, 0xf8, 0x7a, 0xd2, 0xd9, 0xb0, 0x0e, 0x1b, 0xef,
0x19, 0x00, 0x36, 0xe0, 0xda, 0x7f, 0x83, 0x0e, 0xa1, 0x90, 0x1f, 0x70,
0xc7, 0x28, 0xa1, 0x49, 0x2e, 0xda, 0x2a, 0x82, 0xac, 0xf2, 0xef, 0x74,
0xeb, 0xe3, 0x5d, 0xa3, 0x56, 0xb2, 0x80, 0x09, 0xf2, 0xc9, 0x0d, 0x41,
0x4f, 0xf7, 0xfb, 0xb1, 0x8b, 0x17, 0x07, 0x83, 0x2e, 0x65, 0x56, 0x20,
0xdc, 0x99, 0x1e, 0xf8, 0x3b, 0xe1, 0x51, 0xa0, 0x57, 0xc5, 0x57, 0x60,
0x89, 0x1e, 0x24, 0xf1, 0x57, 0x58, 0xad, 0xac, 0x80, 0x07, 0x88, 0x75,
0x31, 0xe2, 0x97, 0x39, 0xe6, 0x92, 0x3a, 0x7d, 0xa2, 0xbf, 0x6e, 0x5d,
0xa7, 0xa9, 0x6b, 0xae, 0xaa, 0xa8, 0x30, 0xb8, 0x97, 0x13, 0x7a, 0x15,
0x7b, 0x20, 0x10, 0xcc, 0xb0, 0x27, 0x0e, 0x1b, 0x10, 0xbd, 0x55, 0xec,
0x4f, 0xd1, 0xa6, 0x59, 0x29, 0x8c, 0x31, 0x72, 0x07, 0x2f, 0x4f, 0x6e,
0xd5, 0xc4, 0x50, 0x20, 0x2d, 0x05, 0x29, 0xf8, 0x6c, 0x8d, 0x41, 0xc4,
0x0e, 0x9c, 0x74, 0x12, 0x3e, 0xc9, 0xa8, 0x0c, 0x35, 0x43, 0x8a, 0x9d,
0x5b, 0xee, 0x53, 0x18, 0xd9, 0xf1, 0x7c, 0xe2, 0xaf, 0xe5, 0x7c, 0x7a,
0x6f, 0xcc, 0x43, 0xae, 0xdb, 0x55, 0xa1, 0x4b, 0x8b, 0x09, 0xeb, 0xd8,
0x57, 0xda, 0x8f, 0x64, 0x8f, 0xf2, 0xb0, 0x3c, 0xee, 0x90, 0x77, 0xdd,
0x37, 0x76, 0x87, 0xfb, 0xbe, 0x4a, 0xb6, 0x75, 0x03, 0x75, 0xf0, 0x2a,
0x92, 0x3c, 0xfe, 0xe1, 0x5c, 0x37, 0x09, 0xc8, 0x55, 0x28, 0xe8, 0x70,
0x37, 0xef, 0x3f, 0x70, 0x71, 0xd9, 0x3b, 0x25, 0x2e, 0x11, 0xc7, 0x71,
0x86, 0x59, 0x0e, 0x5f, 0x1d, 0x24, 0xfe, 0xf9, 0x4f, 0x0a, 0xbb, 0xfe,
0x92, 0x8b, 0x8f, 0x18, 0xa5, 0xaa, 0x68, 0xc3, 0xd4, 0x8f, 0xb8, 0x00,
0x6e, 0x3e, 0x7e, 0x24, 0x12, 0x95, 0xa9, 0x3d, 0xbd, 0xa4, 0x93, 0xc5,
0x67, 0xef, 0x75, 0x11, 0xb2, 0x50, 0x80, 0xc1, 0x19, 0x1b, 0x8c, 0xbc,
0x9b, 0x2d, 0xad, 0xbe, 0xe4, 0x95, 0xe4, 0x82, 0xd1, 0xab, 0xee, 0x29,
0x39, 0x97, 0x8f, 0x92, 0xc5, 0x7e, 0x94, 0x10, 0xe8, 0x8e, 0xbe, 0x05,
0x23, 0xb5, 0xda, 0x8e, 0xe9, 0x79, 0x88, 0x10, 0x22, 0x1f, 0x5c, 0xb9,
0xd9, 0x10, 0x24, 0x28, 0xed, 0xc1, 0xe8, 0xa6, 0x21, 0xee, 0xda, 0x83,
0x82, 0x44, 0x43, 0x13, 0x74, 0x69, 0xb0, 0x33, 0xd0, 0xaf, 0x1a, 0x07,
0x09, 0x46, 0x42, 0xa8, 0xfb, 0x09, 0x81, 0xe5, 0x91, 0x21, 0xe5, 0xcb,
0x1b, 0x0e, 0x26, 0x0c, 0x08, 0x99, 0xbb, 0x0c, 0x3a, 0xdc, 0xcf, 0x0e,
0x9d, 0xc8, 0xc4, 0xee, 0x1a, 0xdc, 0xf5, 0x3d, 0x60, 0x8a, 0xe8, 0x0e,
0xab, 0xbb, 0xad, 0x49, 0xa0, 0x6d, 0x70, 0x9b, 0x85, 0x29, 0x3c, 0x31,
0xf7, 0xed, 0xa5, 0xed, 0xf6, 0x4c, 0x1f, 0x26, 0x0d, 0x06, 0x8b, 0xe7,
0x0f, 0x0c, 0x4c, 0xbe, 0x23, 0xa0, 0xbf, 0x20, 0x76, 0xd3, 0x23, 0x67,
0x7e, 0x64, 0x32, 0x8b, 0x9d, 0xd0, 0x77, 0x4c, 0x3d, 0xb9, 0xb0, 0x71,
0x1c, 0x5d, 0x9a, 0xa8, 0xa7, 0x8d, 0xac, 0x3e, 0xbc, 0xe1, 0x27, 0x45,
0x34, 0xb1, 0x1a, 0x05, 0x60, 0x7b, 0x90, 0xb1, 0x4f, 0x95, 0xa2, 0x19,
0x3f, 0x86, 0xf3, 0x21, 0x0a, 0xfc, 0x6f, 0x55, 0x44, 0xfc, 0x52, 0xde,
0x33, 0x98, 0xc3, 0x1c, 0xca, 0x61, 0xe8, 0x1e, 0x6c, 0xe3, 0x9c, 0xc3,
0xb2, 0xdf, 0x6a, 0x93, 0x4b, 0x71, 0x29, 0x67, 0xe7, 0x26, 0x68, 0x89,
0xda, 0x74, 0x0a, 0xf7, 0x42, 0xcc, 0x3c, 0x2c, 0x78, 0x6a, 0xf4, 0x39,
0x15, 0x30, 0x29, 0xec, 0x87, 0xca, 0xdc, 0x06, 0x7e, 0x25, 0x07, 0x83,
0xd8, 0xc8, 0xfa, 0x21, 0x86, 0x10, 0x29, 0xb4, 0x10, 0xbc, 0x3e, 0xee,
0xe3, 0x5c, 0x56, 0x01, 0x94, 0xbe, 0xa6, 0x63, 0x23, 0x8b, 0x5f, 0x9d,
0x26, 0xc2, 0x6f, 0x86, 0x06, 0x45, 0x2f, 0x01, 0x4c, 0x1c, 0xea, 0x96,
0xdd, 0xb5, 0x1e, 0xbb, 0x28, 0x1a, 0xca, 0x6a, 0xf8, 0x67, 0x82, 0xac,
0xa3, 0x41, 0x7b, 0xa0, 0xc1, 0xfe, 0x34, 0x4f, 0x66, 0x85, 0x90, 0xc5,
0x05, 0x1b, 0xc4, 0x86, 0xde, 0x51, 0xf1, 0x2b, 0x9c, 0x89, 0x46, 0x3c,
0xd6, 0xf7, 0x26, 0xe5, 0xe0, 0xd7, 0x93, 0xac, 0xa3, 0x9c, 0xdb, 0xb0,
0x72, 0x6e, 0x5f, 0xad, 0x9c, 0x08, 0x7b, 0xc2, 0x3f, 0x2e, 0x81, 0xa7,
0xb6, 0xa0, 0x42, 0xd6, 0xdc, 0x80, 0x02, 0xcc, 0x21, 0xb1, 0x82, 0xbf,
0x4b, 0x45, 0x06, 0x5a, 0x4f, 0x45, 0xf4, 0x35, 0x2f, 0x61, 0x45, 0xd1,
0x8a, 0x3f, 0x5b, 0x5d, 0x06, 0x7a, 0x5f, 0x75, 0x31, 0x6f, 0xea, 0xc4,
0xbc, 0xd1, 0xc7, 0x75, 0x3c, 0x29, 0xf7, 0xe8, 0x65, 0xa5, 0x1d, 0x9c,
0xdb, 0x95, 0xfb, 0xaf, 0x0c, 0xb5, 0x93, 0xc7, 0xbb, 0xef, 0xe2, 0x7e,
0xe3, 0xe5, 0x7f, 0x09, 0xae, 0xe2, 0x59, 0x1b, 0xee, 0x3a, 0x3e, 0xb4,
0x8a, 0xd7, 0xd4, 0x2a, 0x1c, 0x63, 0x3b, 0xc3, 0x67, 0xa4, 0x03, 0x57,
0xca, 0xf1, 0xff, 0x26, 0x08, 0xf5, 0xf1, 0x25, 0xfc, 0x8e, 0x22, 0x0b,
0x57, 0x80, 0x79, 0xc1, 0x81, 0x6c, 0xd0, 0xb6, 0x48, 0x36, 0xbf, 0xf3,
0x13, 0x03, 0xe1, 0xe4, 0xa3, 0xae, 0x00, 0xef, 0xa9, 0xc2, 0x8f, 0xdf,
0x7d, 0xf5, 0x73, 0x06, 0x16, 0xe2, 0x87, 0xf0, 0x95, 0x3e, 0x84, 0x87,
0xaf, 0x7e, 0xfe, 0x3a, 0x5d, 0x18, 0xcb, 0x59, 0xb7, 0x53, 0xa6, 0x59,
0x78, 0x75, 0x60, 0x96, 0xbe, 0xa3, 0x82, 0xfb, 0x48, 0xda, 0xfb, 0x11,
0x4a, 0x7e, 0x06, 0xda, 0xa4, 0x70, 0xdf, 0xee, 0xf5, 0x70, 0x54, 0xef,
0xcb, 0x3e, 0x38, 0xd1, 0x4a, 0x96, 0xd0, 0x20, 0xaf, 0x87, 0x60, 0x8f,
0x58, 0x77, 0xec, 0x91, 0x4d, 0x4c, 0xe1, 0xbb, 0xef, 0xbe, 0x7d, 0xda,
0x14, 0x8f, 0x8b, 0x78, 0xdb, 0x2b, 0x7a, 0xe0, 0xa3, 0xde, 0xbe, 0xc6,
0xcf, 0xd8, 0x13, 0x20, 0x60, 0xbc, 0x30, 0x9a, 0xad, 0xbc, 0x83, 0x02,
0x5d, 0xa9, 0xfb, 0x5f, 0xf1, 0x46, 0x2f, 0x67, 0xe3, 0xee, 0x34, 0xcb,
0x90, 0x5d, 0x93, 0xd4, 0x3b, 0x13, 0xc2, 0x19, 0x6d, 0x26, 0x8d, 0x14,
0x48, 0x20, 0x61, 0x7f, 0x50, 0x10, 0xee, 0x84, 0x05, 0xa4, 0x87, 0x86,
0x66, 0x01, 0x9b, 0xc4, 0x66, 0x7e, 0x33, 0xbf, 0x87, 0x9f, 0xf2, 0x90,
0x09, 0xf0, 0xfe, 0xb3, 0x03, 0x9e, 0x5c, 0x00, 0x1c, 0x31, 0xc0, 0x49,
0x35, 0xeb, 0x90, 0x9f, 0x59, 0xa3, 0xdc, 0x2e, 0xff, 0xad, 0xa7, 0x6d,
0xcc, 0x88, 0xf3, 0x0f, 0x1c, 0x1c, 0xe0, 0x13, 0x8c, 0x9c, 0x46, 0xef,
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,275 +1,253 @@
// 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
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
*/
uint16_t handleSegmentOFF(void) {
WS2812FX::Segment* _seg = strip->getSegment();
return _seg->speed;
}
// ***************************************************************************
// Functions and variables for automatic cycling
// Function for automatic cycling
// ***************************************************************************
void handleAutoPlay() {
if (autoDelay <= millis()) {
hex_colors[0] = autoParams[autoCount][0];
hex_colors[1] = autoParams[autoCount][1];
hex_colors[2] = autoParams[autoCount][2];
strip->setColors(selected_segment, hex_colors);
strip->setSpeed(selected_segment, convertSpeed((uint8_t)autoParams[autoCount][3]));
strip->setMode(selected_segment, (uint8_t)autoParams[autoCount][4]);
strip->trigger();
autoDelay = millis() + (uint32_t)autoParams[autoCount][5];
DBG_OUTPUT_PORT.print("autoTick ");
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]);
autoCount++;
if (autoCount >= (sizeof(autoParams) / sizeof(autoParams[0]))) autoCount = 0;
void handleAutoPlay(uint8_t _seg) {
//WS2812FX::Segment* _seg = strip->getSegment();
if (autoDelay[_seg] <= millis()) {
uint32_t _hex_colors[3] = {};
//if (_seg ==
_hex_colors[0] = autoParams[autoCount[_seg]][0];
_hex_colors[1] = autoParams[autoCount[_seg]][1];
_hex_colors[2] = autoParams[autoCount[_seg]][2];
//}
strip->setColors(_seg, _hex_colors);
strip->setSpeed(_seg, convertSpeed((uint16_t)autoParams[autoCount[_seg]][3]));
strip->setMode(_seg, (uint8_t)autoParams[autoCount[_seg]][4]);
//strip->trigger();
autoDelay[_seg] = millis() + (unsigned long)autoParams[autoCount[_seg]][5];
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]);
autoCount[_seg]++;
if (autoCount[_seg] >= (sizeof(autoParams) / sizeof(autoParams[0]))) autoCount[_seg] = 0;
}
}
void handleAuto() {
// Dummy function
uint16_t handleAuto() {
WS2812FX::Segment* _seg = strip->getSegment();
return _seg->speed;
}
void handleCustomWS() {
// Dummy function
}
#if defined(CUSTOM_WS2812FX_ANIMATIONS)
// ***************************************************************************
// TV mode
// ***************************************************************************
uint8_t dipInterval = 10;
uint16_t darkTime = 250;
unsigned long currentDipTime;
unsigned long dipStartTime;
unsigned long currentMillis;
uint8_t ledState = LOW;
long previousMillis = 0;
uint16_t led = 5;
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) {
// Source: https://blog.adafruit.com/2012/03/14/constant-brightness-hsb-to-rgb-algorithm/
uint8_t temp[5], n = (index >> 8) % 3;
temp[0] = temp[3] = (uint8_t)(( (sat ^ 255) * bright) / 255);
temp[1] = temp[4] = (uint8_t)((((( (index & 255) * sat) / 255) + (sat ^ 255)) * bright) / 255);
temp[2] = (uint8_t)(((((((index & 255) ^ 255) * sat) / 255) + (sat ^ 255)) * bright) / 255);
strip->setPixelColor(led, temp[n + 2], temp[n + 1], temp[n], 0);
}
void updateLed (uint16_t led, uint8_t brightness) {
ledstates[led] = brightness;
for (uint16_t i=0; i<WS2812FXStripSettings.stripSize; i++) {
uint16_t index = (i%3 == 0) ? 400 : random(0,767);
hsb2rgbAN1(index, 200, ledstates[i], i);
}
//strip->show();
}
// 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(1000-(ws2812fx_speed*2),5001-(ws2812fx_speed*8));
twitch = random(40,100);// Twitch provides motion effect but can be a bit much if too high
dipCount = dipCount++;
}
if(currentMillis-previousMillis<twitch) {
led=random(0, WS2812FXStripSettings.stripSize - 1);
ledState = ledState == LOW ? HIGH: LOW; // if the LED is off turn it on and vice-versa:
updateLed(led, (ledState) ? 255 : 0);
if (dipCount > dipInterval) {
DBG_OUTPUT_PORT.println("dip");
timeToDip = true;
dipCount = 0;
dipStartTime = millis();
darkTime = random(50,150);
dipInterval = random(5,250);// cycles of flicker
}
}
} else {
DBG_OUTPUT_PORT.println("Dip Time");
currentDipTime = millis();
if (currentDipTime - dipStartTime < darkTime) {
for (uint16_t i=3; i<WS2812FXStripSettings.stripSize; i++) {
updateLed(i, 0);
}
} else {
timeToDip = false;
}
}
}
void handleE131(){
if (!e131->isEmpty())
{
e131_packet_t packet;
e131->pull(&packet); // Pull packet from ring buffer
uint16_t universe = htons(packet.universe);
uint8_t *data = packet.property_values + 1;
if (universe < START_UNIVERSE || universe > END_UNIVERSE) return; //async will take care about filling the buffer
// Serial.printf("Universe %u / %u Channels | Packet#: %u / Errors: %u / CH1: %u\n",
// htons(packet.universe), // The Universe for this packet
// htons(packet.property_value_count) - 1, // Start code is ignored, we're interested in dimmer data
// e131.stats.num_packets, // Packet counter
// e131.stats.packet_errors, // Packet error counter
// packet.property_values[1]); // Dimmer data for Channel 1
/* #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
if (NUMLEDS <= multipacketOffset) return;
uint16_t len = (128 + multipacketOffset > WS2812FXStripSettings.stripSize) ? (WS2812FXStripSettings.stripSize - multipacketOffset) : 128;
#else*/
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;
uint16_t len = (170 + multipacketOffset > WS2812FXStripSettings.stripSize) ? (WS2812FXStripSettings.stripSize - multipacketOffset) : 170;
/* #endif */
for (uint16_t i = 0; i < len; i++){
uint16_t j = i * 3;
/* #if defined(RGBW)
strip->setPixelColor(i + multipacketOffset, data[j], data[j + 1], data[j + 2], data[j + 3]);
#else */
strip->setPixelColor(i + multipacketOffset, data[j], data[j + 1], data[j + 2], 0);
/* #endif */
}
}
}
#include <FastLED.h> //https://github.com/FastLED/FastLED
/*
* 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.
*/
// Fire2012 by Mark Kriegsman, July 2012
// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY
////
// This basic one-dimensional 'fire' simulation works roughly as follows:
// There's a underlying array of 'heat' cells, that model the temperature
// at each point along the line. Every cycle through the simulation,
// four steps are performed:
// 1) All cells cool down a little bit, losing heat to the air
// 2) The heat from each cell drifts 'up' and diffuses a little
// 3) Sometimes randomly new 'sparks' of heat are added at the bottom
// 4) The heat from each cell is rendered as a color into the leds array
// The heat-to-color mapping uses a black-body radiation approximation.
//
// Temperature is in arbitrary units from 0 (cold black) to 255 (white hot).
//
// This simulation scales it self a bit depending on NUM_LEDS; it should look
// "OK" on anywhere from 20 to 100 LEDs without too much tweaking.
//
// I recommend running this simulation at anywhere from 30-100 frames per second,
// meaning an interframe delay of about 10-35 milliseconds.
//
// Looks best on a high-density LED setup (60+ pixels/meter).
//
//
// There are two main parameters you can play with to control the look and
// feel of your fire: COOLING (used in step 1 above), and SPARKING (used
// in step 3 above).
//
// COOLING: How much does the air cool as it rises?
// Less cooling = taller flames. More cooling = shorter flames.
// Default 50, suggested range 20-100
#define COOLING 70
// SPARKING: What chance (out of 255) is there that a new spark will be lit?
// Higher chance = more roaring fire. Lower chance = more flickery fire.
// Default 120, suggested range 50-200.
#define SPARKING 120
bool gReverseDirection = false;
void Fire2012() {
// Array of temperature readings at each simulation cell
// Step 1. Cool down every cell a little
for( uint16_t i = 0; i < WS2812FXStripSettings.stripSize; i++) {
ledstates[i] = qsub8( ledstates[i], random8(0, ((COOLING * 10) / WS2812FXStripSettings.stripSize) + 2));
}
// Step 2. Heat from each cell drifts 'up' and diffuses a little
for( uint16_t k= WS2812FXStripSettings.stripSize - 1; k >= 2; k--) {
ledstates[k] = (ledstates[k - 1] + ledstates[k - 2] + ledstates[k - 2]) / 3;
}
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
if( random8() < SPARKING ) {
uint8_t y = random8(7);
ledstates[y] = qadd8(ledstates[y], random8(160,255) );
}
// Step 4. Map from heat cells to LED colors
for( uint16_t j = 0; j < WS2812FXStripSettings.stripSize; j++) {
CRGB color = HeatColor( ledstates[j]);
uint16_t pixelnumber;
if( gReverseDirection ) {
pixelnumber = (WS2812FXStripSettings.stripSize - 1) - j;
} else {
pixelnumber = j;
}
strip->setPixelColor(pixelnumber, color.red, color.green, color.blue, 0);
}
}
void Gradient() {
for( uint16_t j = 0; j < WS2812FXStripSettings.stripSize; j++) {
uint16_t pixelnumber;
uint32_t color;
if( gReverseDirection ) {
pixelnumber = (WS2812FXStripSettings.stripSize - 1) - j;
} else {
pixelnumber = j;
}
color = trans(strip->getColors(selected_segment)[1], strip->getColors(selected_segment)[0], (j*255)/(WS2812FXStripSettings.stripSize - 1));
strip->setPixelColor(pixelnumber, ((color >> 16) & 0xFF), ((color >> 8) & 0xFF), ((color >> 0) & 0xFF), ((color >> 24) & 0xFF));
}
}
#endif
uint16_t myCustomEffect0() {
handleAuto();
return (strip->getSpeed() / WS2812FXStripSettings.stripSize);
}
uint16_t myCustomEffect1() {
handleCustomWS();
return (strip->getSpeed() / WS2812FXStripSettings.stripSize);
uint16_t handleCustomWS(void) {
WS2812FX::Segment* _seg = strip->getSegment();
return _seg->speed;
}
#if defined(CUSTOM_WS2812FX_ANIMATIONS)
uint16_t myCustomEffect2() {
handleTV();
return (strip->getSpeed() / WS2812FXStripSettings.stripSize);
}
// ***************************************************************************
// TV mode to be reviewed
// ***************************************************************************
uint16_t darkTime[10] = {250,250,250,250,250,250,250,250,250,250};
uint8_t dipInterval[10] = {10,10,10,10,10,10,10,10,10,10};
unsigned long dipStartTime[10] = {};
uint8_t ledState[10] = {LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW,LOW};
unsigned long previousMillis[10]= {0,0,0,0,0,0,0,0,0,0};
uint16_t interv[10] = {2000,2000,2000,2000,2000,2000,2000,2000,2000,2000};
uint8_t twitch[10]= {50,50,50,50,50,50,50,50,50,50};
uint8_t dipCount[10] = {0,0,0,0,0,0,0,0,0,0};
bool timeToDip[10] = {false,false,false,false,false,false,false,false,false,false};
uint16_t myCustomEffect3() {
handleE131();
return (strip->getSpeed() / WS2812FXStripSettings.stripSize);
}
uint16_t myCustomEffect4() {
Fire2012();
return (strip->getSpeed() / WS2812FXStripSettings.stripSize);
}
void hsb2rgbAN1(uint16_t index, uint8_t sat, uint8_t bright, uint16_t led) {
// Source: https://blog.adafruit.com/2012/03/14/constant-brightness-hsb-to-rgb-algorithm/
uint8_t temp[5], n = (index >> 8) % 3;
temp[0] = temp[3] = (uint8_t)(( (sat ^ 255) * bright) / 255);
temp[1] = temp[4] = (uint8_t)((((( (index & 255) * sat) / 255) + (sat ^ 255)) * bright) / 255);
temp[2] = (uint8_t)(((((((index & 255) ^ 255) * sat) / 255) + (sat ^ 255)) * bright) / 255);
strip->setPixelColor(led, temp[n + 2], temp[n + 1], temp[n], 0);
}
uint16_t myCustomEffect5() {
Gradient();
return (strip->getSpeed() / WS2812FXStripSettings.stripSize);
}
uint16_t handleTV(void) {
WS2812FX::Segment* _seg = strip->getSegment();
uint8_t _seg_num = strip->getSegmentIndex();
if (timeToDip[_seg_num] == false) {
if((millis() - previousMillis[_seg_num]) > interv[_seg_num]) {
DBG_OUTPUT_PORT.println("Segment:");
DBG_OUTPUT_PORT.println(_seg_num);
previousMillis[_seg_num] = millis();
//interv = random(750,4001);//Adjusts the interval for more/less frequent random light changes
interv[_seg_num] = random(800-(512 - (_seg->speed/64)),6001-(2731 - (_seg->speed/24)));
twitch[_seg_num] = random(40,100);// Twitch provides motion effect but can be a bit much if too high
dipCount[_seg_num]++;
}
if((millis() - previousMillis[_seg_num]) < twitch[_seg_num]) {
uint16_t led=random(_seg->start, _seg->stop);
ledState[_seg_num] = ledState[_seg_num] == LOW ? HIGH : LOW; // if the LED is off turn it on and vice-versa:
ledstates[led] = ((ledState[_seg_num]) ? 255 : 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);
}
if (dipCount[_seg_num] > dipInterval[_seg_num]) {
timeToDip[_seg_num] = true;
dipCount[_seg_num] = 0;
dipStartTime[_seg_num] = millis();
darkTime[_seg_num] = random(50,150);
dipInterval[_seg_num] = random(5,250);// cycles of flicker
}
}
} else {
DBG_OUTPUT_PORT.println("Dip Time");
if (millis() - dipStartTime[_seg_num] < darkTime[_seg_num]) {
for (uint16_t i=(_seg->start + 3); i<= _seg->stop; i++) {
ledstates[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 {
timeToDip[_seg_num] = false;
}
}
return _seg->speed;
}
// ***************************************************************************
// TV mode
// ***************************************************************************
uint16_t handleE131(void) {
WS2812FX::Segment* _seg = strip->getSegment();
if (!e131->isEmpty()) {
e131_packet_t packet;
e131->pull(&packet); // Pull packet from ring buffer
uint16_t universe = htons(packet.universe);
uint8_t *data = packet.property_values + 1;
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",
// htons(packet.universe), // The Universe for this packet
// htons(packet.property_value_count) - 1, // Start code is ignored, we're interested in dimmer data
// e131.stats.num_packets, // Packet counter
// e131.stats.packet_errors, // Packet error counter
// packet.property_values[1]); // Dimmer data for Channel 1
/* #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
if (NUMLEDS <= multipacketOffset) return;
uint16_t len = (128 + multipacketOffset > Config.stripSize) ? (Config.stripSize - multipacketOffset) : 128;
#else*/
uint16_t multipacketOffset = (universe - START_UNIVERSE) * 170; //if more than 170 LEDs * 3 colors = 510 channels, client will send in next higher universe
if (Config.stripSize <= multipacketOffset) return _seg->speed;
uint16_t len = (170 + multipacketOffset > Config.stripSize) ? (Config.stripSize - multipacketOffset) : 170;
/* #endif */
for (uint16_t i = 0; i < len; i++){
if ((i >= _seg->start) && (i <= _seg->stop)) {
uint16_t j = i * 3;
/* #if defined(RGBW)
strip->setPixelColor(i + multipacketOffset, data[j], data[j + 1], data[j + 2], data[j + 3]);
#else */
strip->setPixelColor(i + multipacketOffset, data[j], data[j + 1], data[j + 2], 0);
/* #endif */
}
}
}
return _seg->speed;
}
/*
* 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.
*/
#include <FastLED.h> //https://github.com/FastLED/FastLED
// Fire2012 by Mark Kriegsman, July 2012
// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY
////
// This basic one-dimensional 'fire' simulation works roughly as follows:
// There's a underlying array of 'heat' cells, that model the temperature
// at each point along the line. Every cycle through the simulation,
// four steps are performed:
// 1) All cells cool down a little bit, losing heat to the air
// 2) The heat from each cell drifts 'up' and diffuses a little
// 3) Sometimes randomly new 'sparks' of heat are added at the bottom
// 4) The heat from each cell is rendered as a color into the leds array
// The heat-to-color mapping uses a black-body radiation approximation.
//
// Temperature is in arbitrary units from 0 (cold black) to 255 (white hot).
//
// This simulation scales it self a bit depending on NUM_LEDS; it should look
// "OK" on anywhere from 20 to 100 LEDs without too much tweaking.
//
// I recommend running this simulation at anywhere from 30-100 frames per second,
// meaning an interframe delay of about 10-35 milliseconds.
//
// Looks best on a high-density LED setup (60+ pixels/meter).
//
//
// There are two main parameters you can play with to control the look and
// feel of your fire: COOLING (used in step 1 above), and SPARKING (used
// in step 3 above).
//
// COOLING: How much does the air cool as it rises?
// Less cooling = taller flames. More cooling = shorter flames.
// Default 50, suggested range 20-100
#define COOLING 70
// SPARKING: What chance (out of 255) is there that a new spark will be lit?
// Higher chance = more roaring fire. Lower chance = more flickery fire.
// Default 120, suggested range 50-200.
#define SPARKING 120
uint16_t handleFire2012(void) {
// Array of temperature readings at each simulation cell
WS2812FX::Segment* _seg = strip->getSegment();
// Step 1. Cool down every cell a little
for( uint16_t i = _seg->start; i <= _seg->stop; i++) {
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
for( uint16_t k= _seg->stop; k >= (_seg->start + 2); k--) {
ledstates[k] = (ledstates[k - 1] + ledstates[k - 2] + ledstates[k - 2]) / 3;
}
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
if( random8() < SPARKING ) {
uint8_t y = random8(7) + _seg->start;
ledstates[y] = qadd8(ledstates[y], random8(160,255) );
}
// Step 4. Map from heat cells to LED colors
for( uint16_t j = _seg->start; j <= _seg->stop; j++) {
CRGB color = HeatColor(ledstates[j]);
uint16_t pixel;
if ((_seg->options & 128) > 0) {
pixel = _seg->stop + (_seg->start - j);
} else {
pixel = j;
}
strip->setPixelColor(pixel, color.red, color.green, color.blue, 0);
}
return _seg->speed;
}
uint16_t handleGradient() {
WS2812FX::Segment* _seg = strip->getSegment();
for(uint16_t j = 0; j <= (_seg->stop - _seg->start); j++) {
uint16_t pixel;
if ((_seg->options & 128) > 0) {
pixel = _seg->stop - j;
} else {
pixel = _seg->start + j;
}
uint32_t color = trans(_seg->colors[1], _seg->colors[0], j, (_seg->stop - _seg->start));
strip->setPixelColor(pixel, ((color >> 16) & 0xFF), ((color >> 8) & 0xFF), ((color >> 0) & 0xFF), ((color >> 24) & 0xFF));
}
return _seg->speed;
}
#endif
File diff suppressed because it is too large Load Diff
+441 -324
View File
@@ -1,359 +1,476 @@
// ***************************************************************************
// Setup: Webserver handler
// ***************************************************************************
//list directory
server.on("/list", HTTP_GET, handleFileList);
//create file
server.on("/edit", HTTP_PUT, handleFileCreate);
//delete file
server.on("/edit", HTTP_DELETE, handleFileDelete);
//first callback is called after the request has ended with all parsed arguments
//second callback handles file uploads at that location
server.on("/edit", HTTP_POST, []() {
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", "");
}, handleFileUpload);
// ***************************************************************************
// Setup: Webserver handler
// ***************************************************************************
//list directory
server.on("/list", HTTP_GET, handleFileList);
//create file
server.on("/edit", HTTP_PUT, handleFileCreate);
//delete file
server.on("/edit", HTTP_DELETE, handleFileDelete);
//first callback is called after the request has ended with all parsed arguments
//second callback handles file uploads at that location
server.on("/edit", HTTP_POST, []() {
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", "");
}, handleFileUpload);
// ***************************************************************************
// Setup: SPIFFS Webserver handler
// ***************************************************************************
server.on("/", HTTP_GET, [&](){
#if defined(USE_HTML_MIN_GZ)
server.sendHeader("Content-Encoding", "gzip", true);
server.send_P(200, PSTR("text/html"), index_htm_gz, index_htm_gz_len);
#else
if (!handleFileRead(server.uri()))
handleNotFound();
#endif
});
server.on("/edit", HTTP_GET, [&](){
#if defined(USE_HTML_MIN_GZ)
server.sendHeader("Content-Encoding", "gzip", true);
server.send_P(200, PSTR("text/html"), edit_htm_gz, edit_htm_gz_len);
#else
if (!handleFileRead("/edit.htm"))
handleNotFound();
#endif
});
//called when the url is not defined here
//use it to load content from SPIFFS
server.onNotFound([]() {
server.on("/", HTTP_GET, [&](){
#if defined(USE_HTML_MIN_GZ)
server.sendHeader("Content-Encoding", "gzip", true);
server.send_P(200, PSTR("text/html"), index_htm_gz, index_htm_gz_len);
#else
if (!handleFileRead(server.uri()))
handleNotFound();
});
#endif
});
server.on("/upload", handleMinimalUpload);
server.on("/edit", HTTP_GET, [&](){
#if defined(USE_HTML_MIN_GZ)
server.sendHeader("Content-Encoding", "gzip", true);
server.send_P(200, PSTR("text/html"), edit_htm_gz, edit_htm_gz_len);
#else
if (!handleFileRead("/edit.htm"))
handleNotFound();
#endif
});
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;
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();
//called when the url is not defined here
//use it to load content from SPIFFS
server.onNotFound([]() {
if (!handleFileRead(server.uri()))
handleNotFound();
});
server.on("/upload", handleMinimalUpload);
server.on("/esp_status", HTTP_GET, []() { //get heap status, analog input value and all GPIO statuses in one json call
getESPStateJSON();
});
server.on("/restart", []() {
DBG_OUTPUT_PORT.printf("/restart\r\n");
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", "restarting..." );
ESP.restart();
});
server.on("/reset_wlan", []() {
DBG_OUTPUT_PORT.printf("/reset_wlan\r\n");
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", "Resetting WLAN and restarting..." );
WiFiManager wifiManager;
wifiManager.resetSettings();
ESP.restart();
});
server.on("/start_config_ap", []() {
DBG_OUTPUT_PORT.printf("/start_config_ap\r\n");
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", "Starting config AP ..." );
WiFiManager wifiManager;
wifiManager.startConfigPortal(HOSTNAME);
});
server.on("/format_spiffs", []() {
DBG_OUTPUT_PORT.printf("/format_spiffs\r\n");
server.send(200, "text/plain", "Formatting SPIFFS ..." );
SPIFFS.format();
});
server.on("/get_brightness", []() {
char str_brightness[4];
snprintf(str_brightness, sizeof(str_brightness), "%i", (int) (State.brightness / 2.55));
str_brightness[sizeof(str_brightness) - 1] = 0x00;
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", str_brightness );
DBG_OUTPUT_PORT.printf("/get_brightness: %i\r\n", (int) (State.brightness / 2.55));
});
server.on("/get_speed", []() {
char str_speed[4];
snprintf(str_speed, sizeof(str_speed), "%i", segState.speed[State.segment]);
str_speed[sizeof(str_speed) - 1] = 0x00;
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", str_speed );
DBG_OUTPUT_PORT.printf("/get_speed: %i\r\n", segState.speed[State.segment]);
});
server.on("/get_switch", []() {
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", (State.mode == OFF) ? "0" : "1" );
DBG_OUTPUT_PORT.printf("/get_switch: %s\r\n", (State.mode == OFF) ? "0" : "1");
});
server.on("/get_color", []() {
char rgbcolor[10];
snprintf(rgbcolor, sizeof(rgbcolor), "%02X%02X%02X%02X", main_color.white, main_color.red, main_color.green, main_color.blue);
rgbcolor[sizeof(rgbcolor) - 1] = 0x00;
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", rgbcolor );
DBG_OUTPUT_PORT.print("/get_color: ");
DBG_OUTPUT_PORT.println(rgbcolor);
});
server.on("/get_color2", []() {
char rgbcolor[10];
snprintf(rgbcolor, sizeof(rgbcolor), "%02X%02X%02X%02X", back_color.white, back_color.red, back_color.green, back_color.blue);
rgbcolor[sizeof(rgbcolor) - 1] = 0x00;
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", rgbcolor );
DBG_OUTPUT_PORT.print("/get_color2: ");
DBG_OUTPUT_PORT.println(rgbcolor);
});
server.on("/get_color3", []() {
char rgbcolor[10];
snprintf(rgbcolor, sizeof(rgbcolor), "%02X%02X%02X%02X", xtra_color.white, xtra_color.red, xtra_color.green, xtra_color.blue);
rgbcolor[sizeof(rgbcolor) - 1] = 0x00;
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", rgbcolor );
DBG_OUTPUT_PORT.print("/get_color3: ");
DBG_OUTPUT_PORT.println(rgbcolor);
});
server.on("/get_modes", []() {
getModesJSON();
});
server.on("/status", []() {
getStateJSON();
});
server.on("/config", []() {
/*
// This will be used later when web-interface is ready and HTTP_GET will not be allowed to update the Strip Settings
if(server.args() == 0 and server.method() != HTTP_POST)
{
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "application/json", buffer);
free (buffer);
});
server.send(200, "text/plain", "Only HTTP POST method is allowed and check the number of arguments!");
return;
}
server.on("/restart", []() {
DBG_OUTPUT_PORT.printf("/restart\r\n");
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", "restarting..." );
ESP.restart();
});
server.on("/reset_wlan", []() {
DBG_OUTPUT_PORT.printf("/reset_wlan\r\n");
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", "Resetting WLAN and restarting..." );
WiFiManager wifiManager;
wifiManager.resetSettings();
ESP.restart();
});
server.on("/start_config_ap", []() {
DBG_OUTPUT_PORT.printf("/start_config_ap\r\n");
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", "Starting config AP ..." );
WiFiManager wifiManager;
wifiManager.startConfigPortal(HOSTNAME);
});
server.on("/format_spiffs", []() {
DBG_OUTPUT_PORT.printf("/format_spiffs\r\n");
server.send(200, "text/plain", "Formatting SPIFFS ..." );
SPIFFS.format();
});
server.on("/get_brightness", []() {
char str_brightness[4];
snprintf(str_brightness, sizeof(str_brightness), "%i", (int) (brightness / 2.55));
str_brightness[sizeof(str_brightness) - 1] = 0x00;
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", str_brightness );
DBG_OUTPUT_PORT.printf("/get_brightness: %i\r\n", (int) (brightness / 2.55));
});
server.on("/get_speed", []() {
char str_speed[4];
snprintf(str_speed, sizeof(str_speed), "%i", ws2812fx_speed);
str_speed[sizeof(str_speed) - 1] = 0x00;
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", str_speed );
DBG_OUTPUT_PORT.printf("/get_speed: %i\r\n", ws2812fx_speed);
});
server.on("/get_switch", []() {
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", (mode == OFF) ? "0" : "1" );
DBG_OUTPUT_PORT.printf("/get_switch: %s\r\n", (mode == OFF) ? "0" : "1");
});
server.on("/get_color", []() {
char rgbcolor[10];
snprintf(rgbcolor, sizeof(rgbcolor), "%02X%02X%02X%02X", main_color.white, main_color.red, main_color.green, main_color.blue);
rgbcolor[sizeof(rgbcolor) - 1] = 0x00;
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", rgbcolor );
DBG_OUTPUT_PORT.print("/get_color: ");
DBG_OUTPUT_PORT.println(rgbcolor);
});
server.on("/get_color2", []() {
char rgbcolor[10];
snprintf(rgbcolor, sizeof(rgbcolor), "%02X%02X%02X%02X", back_color.white, back_color.red, back_color.green, back_color.blue);
rgbcolor[sizeof(rgbcolor) - 1] = 0x00;
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", rgbcolor );
DBG_OUTPUT_PORT.print("/get_color2: ");
DBG_OUTPUT_PORT.println(rgbcolor);
});
server.on("/get_color3", []() {
char rgbcolor[10];
snprintf(rgbcolor, sizeof(rgbcolor), "%02X%02X%02X%02X", xtra_color.white, xtra_color.red, xtra_color.green, xtra_color.blue);
rgbcolor[sizeof(rgbcolor) - 1] = 0x00;
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", rgbcolor );
DBG_OUTPUT_PORT.print("/get_color3: ");
DBG_OUTPUT_PORT.println(rgbcolor);
});
server.on("/get_modes", []() {
getModesJSON();
});
server.on("/status", []() {
getStatusJSON();
});
server.on("/config", []() {
/*
// This will be used later when web-interface is ready and HTTP_GET will not be allowed to update the Strip Settings
if(server.args() == 0 and server.method() != HTTP_POST)
{
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(200, "text/plain", "Only HTTP POST method is allowed and check the number of arguments!");
return;
}
*/
bool updateStrip = false;
bool updateConf = false;
if(server.hasArg("ws_cnt")){
uint16_t pixelCt = server.arg("ws_cnt").toInt();
if (pixelCt > 0) {
WS2812FXStripSettings.stripSize = constrain(pixelCt, 1, MAXLEDS);
updateStrip = true;
*/
// ToDo do not save if no change
bool _updateStrip = 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_rgbo")){
char tmp_rgbOrder[5];
snprintf(tmp_rgbOrder, sizeof(tmp_rgbOrder), "%s", server.arg("ws_rgbo").c_str());
tmp_rgbOrder[sizeof(tmp_rgbOrder) - 1] = 0x00;
checkRGBOrder(tmp_rgbOrder);
updateStrip = true;
}
if(server.hasArg("ws_cnt")){
uint16_t _stripSize = server.arg("ws_cnt").toInt();
if (_stripSize > 0) {
_stripSize = constrain(_stripSize, 1, MAXLEDS);
if (_stripSize != Config.stripSize) {
Config.stripSize = _stripSize;
_updateStrip = true;
}
}
}
if(server.hasArg("ws_rgbo")){
char _ws_rgbo[5];
snprintf(_ws_rgbo, sizeof(_ws_rgbo), "%s", server.arg("ws_rgbo").c_str());
_ws_rgbo[sizeof(_ws_rgbo) - 1] = 0x00;
checkRGBOrder(_ws_rgbo);
_updateStrip = true;
}
#if !defined(USE_WS2812FX_DMA)
if(server.hasArg("ws_pin")){
if (checkPin(server.arg("ws_pin").toInt())) {
updateStrip = true;
DBG_OUTPUT_PORT.print("Pin was set to: ");
DBG_OUTPUT_PORT.println(WS2812FXStripSettings.pin);
} else {
DBG_OUTPUT_PORT.println("invalid input!");
}
if(server.hasArg("ws_pin")){
if (checkPin(server.arg("ws_pin").toInt())) {
_updateStrip = true;
DBG_OUTPUT_PORT.print("Pin was set to: ");
DBG_OUTPUT_PORT.println(Config.pin);
} else {
DBG_OUTPUT_PORT.println("invalid input or same value!");
}
}
#endif
if(server.hasArg("ws_fxopt")){
WS2812FXStripSettings.fxoptions = ((constrain(server.arg("ws_fxopt").toInt(), 0, 255)>>1)<<1);
updateStrip = true;
}
if(_updateStrip) {
initStrip();
}
if(updateStrip) {
mode = INIT_STRIP;
}
if(server.hasArg("hostname")){
snprintf(HOSTNAME, sizeof(HOSTNAME), "%s", server.arg("hostname").c_str());
HOSTNAME[sizeof(HOSTNAME) - 1] = 0x00;
updateConf = true;
if(server.hasArg("hostname")){
char _hostname[sizeof(HOSTNAME)];
snprintf(_hostname, sizeof(_hostname), "%s", server.arg("hostname").c_str());
_hostname[sizeof(_hostname) - 1] = 0x00;
if (strcmp(HOSTNAME, _hostname) != 0) {
strcpy(HOSTNAME, _hostname);
_updateConfig = true;
}
}
#if defined(ENABLE_MQTT)
if(server.hasArg("mqtt_host")){
snprintf(mqtt_host, sizeof(mqtt_host), "%s", server.arg("mqtt_host").c_str());
mqtt_host[sizeof(mqtt_host) - 1] = 0x00;
updateConf = true;
if(server.hasArg("mqtt_host")){
char _mqtt_host[sizeof(mqtt_host)];
snprintf(_mqtt_host, sizeof(_mqtt_host), "%s", server.arg("mqtt_host").c_str());
_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.arg("mqtt_port").toInt() >= 0) && (server.arg("mqtt_port").toInt() <=65535)) {
mqtt_port = server.arg("mqttport").toInt();
updateConf = true;
}
}
if(server.hasArg("mqtt_port")){
uint16_t _mqtt_port = constrain(server.arg("mqtt_port").toInt(), 1, 65535);
if (_mqtt_port != mqtt_port) {
mqtt_port = _mqtt_port;
_updateConfig = true;
}
if(server.hasArg("mqtt_user")){
snprintf(mqtt_user, sizeof(mqtt_user), "%s", server.arg("mqtt_user").c_str());
mqtt_user[sizeof(mqtt_user) - 1] = 0x00;
updateConf = true;
}
if(server.hasArg("mqtt_user")){
char _mqtt_user[sizeof(mqtt_user)];
snprintf(_mqtt_user, sizeof(_mqtt_user), "%s", server.arg("mqtt_user").c_str());
_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")){
snprintf(mqtt_pass, sizeof(mqtt_pass), "%s", server.arg("mqtt_pass").c_str());
mqtt_pass[sizeof(mqtt_pass) - 1] = 0x00;
updateConf = true;
}
if (updateConf) {
initMqtt();
}
if(server.hasArg("mqtt_pass")){
char _mqtt_pass[sizeof(mqtt_pass)];
snprintf(_mqtt_pass, sizeof(_mqtt_pass), "%s", server.arg("mqtt_pass").c_str());
_mqtt_pass[sizeof(_mqtt_pass) - 1] = 0x00;
if (strcmp(mqtt_pass, _mqtt_pass) != 0) {
strcpy(mqtt_pass, _mqtt_pass);
_updateConfig = true;
}
}
if (_updateConfig) {
initMqtt();
}
#endif
if(server.hasArg("trans_effect")){
transEffect = server.arg("trans_effect").toInt();
updateConf = true;
}
if(server.hasArg("trans_effect")){
Config.transEffect = server.arg("trans_effect").toInt();
_updateConfig = true;
}
#if defined(ENABLE_STATE_SAVE)
if (updateStrip || updateConf) {
if(!settings_save_conf.active()) settings_save_conf.once(3, tickerSaveConfig);
}
if (_updateStrip || _updateConfig) {
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
updateStrip = false;
updateConf = false;
getConfigJSON();
});
_updateStrip = false;
_updateConfig = false;
_updateState = false;
getConfigJSON();
});
server.on("/off", []() {
mode = OFF;
getStatusJSON();
});
server.on("/off", []() {
if (State.mode == OFF) { State.mode = SET; } else { State.mode = OFF; };
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", []() {
mode = SET;
getStatusJSON();
});
server.on("/on", []() {
if (prevmode == OFF) {
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", []() {
prevmode = HOLD;
ws2812fx_mode = FX_MODE_STATIC;
mode = SET;
getArgs();
getStatusJSON();
});
server.on("/set", []() {
prevmode = HOLD;
boolean _updateState = false;
boolean _updateSegState = false;
// Segment
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
* further code changes
* 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");
mkfile.innerHTML = '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(){
if (xmlHttp.readyState == 4){
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 class="flex xs12 sm7">
<div class="flex xs12 sm8">
<div class="sliders container">
<div class="color-wrap" style="display:none">
<div id="color-display"></div>
@@ -912,6 +912,13 @@ input[type=number], label{
<input type="number" id="speedNum">
<input value="255" type="range" min="0" max="255" id="speed">
</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="wsmessageLbl" style="text-align: left;"><p>wsMessage</p>
<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 class="layout row wrap">
<div class="flex xs12 sm4"><p>selectCount</p>
<input type="number" min="0" max="65535" id="selectcount" style="border: 2px solid #aaaaaa; border-radius: 6px; width:100%;" />
<div class="flex xs12 sm3"><p>selectSegCnt</p>
<input type="number" min="1" max="9" id="selectsegcnt" style="border: 2px solid #aaaaaa; border-radius: 6px; width:50%;" />
</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>
</div>
<div class="flex xs12 sm4"><p>selectPin</p>
<input type="number" min="0" max="16" id="selectpin" style="border: 2px solid #aaaaaa; border-radius: 6px; width:100%;" />
<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: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 class="layout row wrap">
@@ -1030,6 +1048,7 @@ var language = {
connectError2: " times. Please use the RECONNECT button to try again.",
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)
loadConfig: "Loading configuration ...",
loadWebsock: "Connecting websockets ...",
loadReady: "Ready ...",
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",
not_greater: "cannot enter numbers greater than 255",
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:",
selectLanguage: "Select Language:",
selectHostname: "Hostname:",
@@ -1050,6 +1072,7 @@ var language = {
selectMQTTPort: "and Port:",
selectMQTTUser: "MQTT Username:",
selectMQTTPass: "MQTT Password:",
selectSegCnt: "Number of Segments:",
selectCount: "Strip LED Count:",
selectRGBO: "RGB Order:",
selectPin: "Strip GPIO Pin:",
@@ -1086,6 +1109,7 @@ var language = {
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)
loadSettings: "Instellingen laden...", // This language-string is not translated (settings not loaded yet)
loadConfig: "Configuratie laden ...",
loadWebsock: "Websockets verbinden...",
loadReady: "Klaar...",
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",
not_greater: "Geen nummers hoger dan 255",
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:",
selectLanguage: "Selecteer Taal:",
selectHostname: "Hostname:",
@@ -1106,6 +1133,7 @@ var language = {
selectMQTTPort: "en Port:",
selectMQTTUser: "MQTT gebruikersnaam:",
selectMQTTPass: "MQTT wachtwoord:",
selectSegCnt: "Number of Segments:",
selectCount: "LED nummer:",
selectPin: "Strip GPIO Pin:",
selectRGBO: "RGB Order:",
@@ -1142,6 +1170,7 @@ var language = {
connectError2: " mal versucht. Benutze WIEDER VERBINDEN, um es nochmal zu probieren.",
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)
loadConfig: "Lade Konfiguration ...",
loadWebsock: "Verbinde Websockets ...",
loadReady: "Fertig ...",
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ß",
not_greater: "Akzeptiere keine Nummern größer 255",
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:",
selectLanguage: "Sprache auswählen:",
selectHostname: "Hostname:",
@@ -1162,6 +1194,7 @@ var language = {
selectMQTTPort: "und Port:",
selectMQTTUser: "MQTT Username:",
selectMQTTPass: "MQTT Password:",
selectSegCnt: "Anzahl Segmente:",
selectCount: "Strip LED Anzahl:",
selectRGBO: "RGB Reihenfolge:",
selectPin: "Strip GPIO Pin:",
@@ -1281,19 +1314,31 @@ var config = {
mqtt_port: 0,
mqtt_user: "",
mqtt_pass: "",
ws_seg: 1,
ws_cnt: 0,
ws_rgbo: "",
ws_pin: 0,
ws_fxopt: 0,
enable_rgbw: false,
transitionEffects: true
ws_trans: false,
enable_rgbw: false
};
var data = {
var state = {
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"},
brightness: 192,
speed: 192,
ws2812fx_mode: null,
ws_fxopt: 0
}
var data = {
init: true,
color_num: 1,
modes: [],
connection: null,
@@ -1301,7 +1346,6 @@ var data = {
num_additional_connections: 0,
is_connected: false,
refresh_interval: 0,
init: true,
color_disabled: false
};
var sendIt; // Timer to prevent lots of sending
@@ -1331,17 +1375,17 @@ function displayColors(all = false) {
clearTimeout(sendIt);
sendIt = setTimeout(function() { set_color(); }, 50);
} else {
document.getElementById("colorSel1").style.backgroundColor = `rgb(${data.color.r}, ${data.color.g}, ${data.color.b})`;
document.getElementById("colorHex1").innerHTML = "#" + data.color.hex;
document.getElementById("colorSel2").style.backgroundColor = `rgb(${data.color.r2}, ${data.color.g2}, ${data.color.b2})`;
document.getElementById("colorHex2").innerHTML = "#" + data.color.hex2;
document.getElementById("colorSel3").style.backgroundColor = `rgb(${data.color.r3}, ${data.color.g3}, ${data.color.b3})`;
document.getElementById("colorHex3").innerHTML = "#" + data.color.hex3;
document.getElementById("colorSel1").style.backgroundColor = `rgb(${segstate.color.r}, ${segstate.color.g}, ${segstate.color.b})`;
document.getElementById("colorHex1").innerHTML = "#" + segstate.color.hex;
document.getElementById("colorSel2").style.backgroundColor = `rgb(${segstate.color.r2}, ${segstate.color.g2}, ${segstate.color.b2})`;
document.getElementById("colorHex2").innerHTML = "#" + segstate.color.hex2;
document.getElementById("colorSel3").style.backgroundColor = `rgb(${segstate.color.r3}, ${segstate.color.g3}, ${segstate.color.b3})`;
document.getElementById("colorHex3").innerHTML = "#" + segstate.color.hex3;
}
}
// initial color val numbers when DOM is loaded
function colorNumrVals(){
function colorNumVals(){
redNumVal.value = red.value;
greenNumVal.value = green.value;
blueNumVal.value = blue.value;
@@ -1377,44 +1421,44 @@ function initSliderColors(){
function changeRangeNumVal(){
redNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255
red.value = checkNumVal(redNumVal, red.value);
if (data.color_num === 1) data.color.r = red.value;
if (data.color_num === 2) data.color.r2 = red.value;
if (data.color_num === 3) data.color.r3 = red.value;
red.value = checkNumVal8(redNumVal, red.value);
if (data.color_num === 1) segstate.color.r = red.value;
if (data.color_num === 2) segstate.color.r2 = red.value;
if (data.color_num === 3) segstate.color.r3 = red.value;
initSliderColors();
displayColors();
});
greenNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255
green.value = checkNumVal(greenNumVal, green.value);
if (data.color_num === 1) data.color.g = green.value;
if (data.color_num === 2) data.color.g2 = green.value;
if (data.color_num === 3) data.color.g3 = green.value;
green.value = checkNumVal8(greenNumVal, green.value);
if (data.color_num === 1) segstate.color.g = green.value;
if (data.color_num === 2) segstate.color.g2 = green.value;
if (data.color_num === 3) segstate.color.g3 = green.value;
initSliderColors();
displayColors();
});
blueNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255
blue.value = checkNumVal(blueNumVal, blue.value);
if (data.color_num === 1) data.color.b = blue.value;
if (data.color_num === 2) data.color.b2 = blue.value;
if (data.color_num === 3) data.color.b3 = blue.value;
blue.value = checkNumVal8(blueNumVal, blue.value);
if (data.color_num === 1) segstate.color.b = blue.value;
if (data.color_num === 2) segstate.color.b2 = blue.value;
if (data.color_num === 3) segstate.color.b3 = blue.value;
initSliderColors();
displayColors();
});
whiteNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255
white.value = checkNumVal(whiteNumVal, white.value);
if (data.color_num === 1) data.color.w = white.value;
if (data.color_num === 2) data.color.w2 = white.value;
if (data.color_num === 3) data.color.w3 = white.value;
white.value = checkNumVal8(whiteNumVal, white.value);
if (data.color_num === 1) segstate.color.w = white.value;
if (data.color_num === 2) segstate.color.w2 = white.value;
if (data.color_num === 3) segstate.color.w3 = white.value;
initSliderColors();
displayColors();
});
brightNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255
bright.value = checkNumVal(brightNumVal, bright.value);
data.brightness = bright.value;
bright.value = checkNumVal8(brightNumVal, bright.value);
state.brightness = bright.value;
initSliderColors();
// Send Brightness
clearTimeout(sendIt);
@@ -1422,14 +1466,14 @@ function changeRangeNumVal(){
});
speedNumVal.addEventListener('change', ()=>{
// make sure numbers are entered between 0 to 255
speed.value = checkNumVal(speedNumVal, speed.value);
data.speed = speed.value;
speed.value = checkNumVal8(speedNumVal, speed.value);
segstate.speed = speed.value;
// Send Speed
clearTimeout(sendIt);
sendIt = setTimeout(function() { set_speed(); }, 50);
});
}
function checkNumVal(numVal, curVal) {
function checkNumVal8(numVal, curVal) {
if(numVal.value > 255) {
alert(language[settings.lang]["not_greater"]);
numVal.value = curVal;
@@ -1440,6 +1484,17 @@ function checkNumVal(numVal, curVal) {
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
function initcolorSliders(){
var event = new Event('change');
@@ -1447,7 +1502,7 @@ function initcolorSliders(){
displayColors();
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
// Trigger onChange event to send value
redNumVal.dispatchEvent(event);
});
@@ -1456,7 +1511,7 @@ function initcolorSliders(){
displayColors();
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
// Trigger onChange event to send value
greenNumVal.dispatchEvent(event);
});
@@ -1465,7 +1520,7 @@ function initcolorSliders(){
displayColors();
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
// Trigger onChange event to send value
blueNumVal.dispatchEvent(event);
});
@@ -1474,7 +1529,7 @@ function initcolorSliders(){
displayColors();
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
// Trigger onChange event to send value
whiteNumVal.dispatchEvent(event);
});
@@ -1482,14 +1537,14 @@ function initcolorSliders(){
bright.addEventListener('input', () => {
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
// Trigger onChange event to send value
brightNumVal.dispatchEvent(event);
});
speed.addEventListener('input', () => {
changeRangeNumVal();
colorNumrVals();
colorNumVals();
// Trigger onChange event to send value
speedNumVal.dispatchEvent(event);
});
@@ -1518,8 +1573,11 @@ function xhttp(url, post, callback) {
xhr.send(post);
}
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) {
//console.log("Getting modes list via REST:", e);
console.log("Getting modes list via REST:", e);
if (e && e.substring(0,6) !== "ERROR!") {
modes = JSON.parse(e);
if (typeof modes[0] !== "undefined") {
@@ -1538,6 +1596,9 @@ function getModes() {
}
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) {
console.log("Getting config via REST:", e);
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_user !== "undefined") config.mqtt_user = res.mqtt_user;
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_rgbo !== "undefined") {
config.ws_rgbo = res.ws_rgbo;
config.enable_rgbw = config.ws_rgbo.includes("W");
}
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.transEffect !== "undefined") config.transitionEffects = res.transEffect;
if (typeof res.ws_trans !== "undefined") config.ws_trans = res.ws_trans;
}
} else {
console.error(e);
@@ -1567,9 +1628,9 @@ function getConfig() {
} else {
document.getElementById("white").parentNode.className = "hidden";
white.value = 0;
data.color.w = 0;
data.color.w2 = 0;
data.color.w3 = 0;
segstate.color.w = 0;
segstate.color.w2 = 0;
segstate.color.w3 = 0;
}
});
}
@@ -1600,11 +1661,11 @@ function showModes(mode, index) {
document.getElementById("modes").appendChild(div);
}
function readSettings() {
document.getElementById("percentage").innerHTML = "33%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "33,100");
document.getElementById("percentage").innerHTML = "25%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "25,100");
document.getElementById("modal-content").innerHTML = language.en.loadSettings;
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) : {};
// Replace default settings with saved ones
for (var set in settings) {
@@ -1612,8 +1673,12 @@ function readSettings() {
if (typeof(tmpsettings[set]) !== "undefined") settings[set] = tmpsettings[set];
}
applySettings();
if (e && e.substring(0,6) !== "ERROR!") connectAdditionalNodes();
else console.warn("ERROR loading settings", e);
if (e && e.substring(0,6) !== "ERROR!") {
connectAdditionalNodes();
} else {
console.warn("ERROR loading settings", e);
saveSettings();
}
});
}
function applySettings() {
@@ -1678,13 +1743,13 @@ function onSelectColNum(colnum) {
x = document.getElementById("colorSel" + colnum);
x.className = x.className.replace(/\belevation-3\b/g, "elevation-9");
// Set ColorPicker and Sliders to selected color
red.value = data.color["r" + (colnum > 1 ? colnum : "")];
green.value = data.color["g" + (colnum > 1 ? colnum : "")];
blue.value = data.color["b" + (colnum > 1 ? colnum : "")];
white.value = data.color["w" + (colnum > 1 ? colnum : "")];
red.value = segstate.color["r" + (colnum > 1 ? colnum : "")];
green.value = segstate.color["g" + (colnum > 1 ? colnum : "")];
blue.value = segstate.color["b" + (colnum > 1 ? colnum : "")];
white.value = segstate.color["w" + (colnum > 1 ? colnum : "")];
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
}
function initSettings() {
// Add languages to language select
@@ -1736,11 +1801,33 @@ function initSettings() {
config.mqtt_pass = mqtt_pass.value;
ws_send("Cmw" + config.mqtt_pass);
});
var count = document.getElementById("selectcount");
count.value = config.ws_cnt;
count.addEventListener('change', ()=>{
config.ws_cnt = count.value;
ws_send("Csc" + config.ws_cnt);
var selsegment = document.getElementById("selectseg");
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;
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");
pin.value = config.ws_pin;
@@ -1760,6 +1847,28 @@ function initSettings() {
config.ws_rgbo = rgbo.value;
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");
for (var code in selectoptrev) {
var option = document.createElement("OPTION");
@@ -1767,10 +1876,10 @@ function initSettings() {
option.innerHTML = selectoptrev[code];
optrev.appendChild(option);
}
optrev.value = (config.ws_fxopt & 128);
optrev.value = (segstate.ws_fxopt & 128);
optrev.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt);
segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("So" + segstate.ws_fxopt);
});
var optfade = document.getElementById("selectoptfade");
for (var code in selectoptfade) {
@@ -1779,10 +1888,10 @@ function initSettings() {
option.innerHTML = selectoptfade[code];
optfade.appendChild(option);
}
optfade.value = (config.ws_fxopt & 112);
optfade.value = (segstate.ws_fxopt & 112);
optfade.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt);
segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("So" + segstate.ws_fxopt);
});
var optgamma = document.getElementById("selectoptgamma");
for (var code in selectoptgamma) {
@@ -1791,10 +1900,10 @@ function initSettings() {
option.innerHTML = selectoptgamma[code];
optgamma.appendChild(option);
}
optgamma.value = (config.ws_fxopt & 8);
optgamma.value = (segstate.ws_fxopt & 8);
optgamma.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt);
segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("So" + segstate.ws_fxopt);
});
var optsize = document.getElementById("selectoptsize");
for (var code in selectoptsize) {
@@ -1803,10 +1912,10 @@ function initSettings() {
option.innerHTML = selectoptsize[code];
optsize.appendChild(option);
}
optsize.value = (config.ws_fxopt & 6)
optsize.value = (segstate.ws_fxopt & 6)
optsize.addEventListener('change', ()=>{
config.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("Cso" + config.ws_fxopt);
segstate.ws_fxopt = optrev.value | optfade.value | optgamma.value | optsize.value;
ws_send("So" + segstate.ws_fxopt);
});
slavenodes.value = settings.slave_nodes;
lang.addEventListener('change', ()=>{
@@ -1820,9 +1929,9 @@ function initSettings() {
redrawColorPicker();
});
var settransitionEffects = document.getElementById("set-transitionEffects");
settransitionEffects.checked = config.transitionEffects;
settransitionEffects.checked = config.ws_trans;
settransitionEffects.addEventListener('change', ()=>{
config.transitionEffects = settransitionEffects.checked;
config.ws_trans = settransitionEffects.checked;
if (settransitionEffects.checked) {
document.getElementById("settransitionEffectsbgcolor").style.backgroundColor = settings.theme_btn;
ws_send("Ce1");
@@ -1855,6 +1964,7 @@ function initSettings() {
settings.theme_back = colback.value;
document.getElementById("container").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("selectoptrev").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++) {
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("redNum").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() {
data.connection = new ReconnectingWebSocket(ws_url, "arduino", ws_options);
document.getElementById("percentage").innerHTML = "67%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "67,100");
document.getElementById("percentage").innerHTML = "75%";
document.getElementById("percentage-done").setAttribute("stroke-dasharray", "75,100");
document.getElementById("modal-content").innerHTML = language[settings.lang].loadWebsock;
// When the connection is open, send some data to the server
@@ -2031,12 +2142,12 @@ function ws_connect() {
con.className = "hidden";
con = document.getElementById("connected");
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("C"); }, 3000);
//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
@@ -2069,53 +2180,56 @@ function ws_connect() {
// document.getElementById('modal').style.display = "none";
// console.log("res", res);
if (res) {
// Status starts here
if (typeof res.mode !== "undefined") data.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.segment !== "undefined") { state.segment= res.segment; document.getElementById("selectseg").value = state.segment; }
if (typeof res.mode !== "undefined") { state.mode = res.mode; }
if (typeof res.brightness !== "undefined") {
data.brightness = res.brightness;
state.brightness = res.brightness;
// init ColorSliderVals
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") {
data.color.w = res.color[0];
data.color.r = res.color[1];
data.color.g = res.color[2];
data.color.b = res.color[3];
data.color.hex = rgbToHex([res.color[0], res.color[1], res.color[2], res.color[3]]);
data.color.w2 = res.color[4];
data.color.r2 = res.color[5];
data.color.g2 = res.color[6];
data.color.b2 = res.color[7];
data.color.hex2 = rgbToHex([res.color[4], res.color[5], res.color[6], res.color[7]]);
data.color.w3 = res.color[8];
data.color.r3 = res.color[9];
data.color.g3 = res.color[10];
data.color.b3 = res.color[11];
data.color.hex3 = rgbToHex([res.color[8], res.color[9], res.color[10], res.color[11]]);
segstate.color.w = res.color[0];
segstate.color.r = res.color[1];
segstate.color.g = res.color[2];
segstate.color.b = res.color[3];
segstate.color.hex = rgbToHex([res.color[0], res.color[1], res.color[2], res.color[3]]);
segstate.color.w2 = res.color[4];
segstate.color.r2 = res.color[5];
segstate.color.g2 = res.color[6];
segstate.color.b2 = res.color[7];
segstate.color.hex2 = rgbToHex([res.color[4], res.color[5], res.color[6], res.color[7]]);
segstate.color.w3 = res.color[8];
segstate.color.r3 = res.color[9];
segstate.color.g3 = res.color[10];
segstate.color.b3 = res.color[11];
segstate.color.hex3 = rgbToHex([res.color[8], res.color[9], res.color[10], res.color[11]]);
// init ColorSliderVals
if (data.color_num === 1) {
red.value = data.color.r;
green.value = data.color.g;
blue.value = data.color.b;
white.value = data.color.w;
red.value = segstate.color.r;
green.value = segstate.color.g;
blue.value = segstate.color.b;
white.value = segstate.color.w;
}
if (data.color_num === 2) {
red.value = data.color.r2;
green.value = data.color.g2;
blue.value = data.color.b2;
white.value = data.color.w2;
red.value = segstate.color.r2;
green.value = segstate.color.g2;
blue.value = segstate.color.b2;
white.value = segstate.color.w2;
}
if (data.color_num === 3) {
red.value = data.color.r3;
green.value = data.color.g3;
blue.value = data.color.b3;
white.value = data.color.w3;
red.value = segstate.color.r3;
green.value = segstate.color.g3;
blue.value = segstate.color.b3;
white.value = segstate.color.w3;
}
}
// 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_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.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_rgbo !== "undefined") {
config.ws_rgbo = res.ws_rgbo;
@@ -2134,19 +2249,20 @@ function ws_connect() {
} else {
document.getElementById("white").parentNode.className = "hidden";
white.value = 0;
data.color.w = 0;
data.color.w2 = 0;
data.color.w3 = 0;
segstate.color.w = 0;
segstate.color.w2 = 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_trans !== "undefined") { config.ws_trans = res.ws_trans; document.getElementById("set-transitionEffects").value = config.ws_trans; }
if (typeof res.ws_fxopt !== "undefined") {
config.ws_fxopt = res.ws_fxopt;
document.getElementById("selectoptrev").value = (config.ws_fxopt & 128);
document.getElementById("selectoptfade").value = (config.ws_fxopt & 112);
document.getElementById("selectoptgamma").value = (config.ws_fxopt & 8);
document.getElementById("selectoptsize").value = (config.ws_fxopt & 6);
segstate.ws_fxopt = res.ws_fxopt;
document.getElementById("selectoptrev").value = (segstate.ws_fxopt & 128);
document.getElementById("selectoptfade").value = (segstate.ws_fxopt & 112);
document.getElementById("selectoptgamma").value = (segstate.ws_fxopt & 8);
document.getElementById("selectoptsize").value = (segstate.ws_fxopt & 6);
}
// Modes starts here
if (typeof res[0] !== "undefined") {
@@ -2157,18 +2273,22 @@ function ws_connect() {
});
}
// init Color Vals
colorNumrVals();
colorNumVals();
initSliderColors();
// init Change Range Val
changeRangeNumVal();
// init Colors controls
// init display Colors
displayColors(true);
console.log("displayColors finished!");
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
//document.getElementById(data.ws2812fx_mode).style.backgroundColor = settings.theme_btnsel;
//document.getElementById(segstate.mode).style.backgroundColor = settings.theme_btnsel;
// Close Loading Modal
setTimeout(() => {
document.getElementById('modal').style.display = "none";
@@ -2212,38 +2332,45 @@ function select_active_button() {
for (i = 0; i < btns.length; i++) {
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");
var arr = wsmess.className.split(" ");
if (arr.indexOf("hidden") === -1) {
wsmess.className += " hidden";
}
segments = document.getElementById("segments");
segments.className = segments.className.replace(/\b hidden\b/g, "");
}
if (data.mode >= 1) {
document.getElementById(data.ws2812fx_mode).style.backgroundColor = settings.theme_btnsel;
if (data.ws2812fx_mode === 56) { // AUTOPLAY
if (state.mode >= 1) {
document.getElementById(segstate.mode).style.backgroundColor = settings.theme_btnsel;
if (segstate.mode == 56) { // AUTOPLAY
disable_modebuttons(false);
disable_color_selection(true);
disable_bright_selection(false);
disable_speed_selection(true);
} else if (data.ws2812fx_mode === 57) { //CUSTOM_WS
} else if (segstate.mode == 57) { //CUSTOM_WS
wsmess = document.getElementById("message");
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_color_selection(true);
disable_bright_selection(false);
disable_speed_selection(true);
} else if (data.ws2812fx_mode === 58) { //TV
} else if (segstate.mode == 58) { //TV
disable_modebuttons(false);
disable_color_selection(true);
disable_bright_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_color_selection(true);
disable_bright_selection(false);
disable_speed_selection(true);
} else if (data.ws2812fx_mode === 60) { //Fire2012
} else if (segstate.mode == 60) { //Fire2012
disable_modebuttons(false);
disable_color_selection(true);
disable_bright_selection(false);
@@ -2254,7 +2381,7 @@ function select_active_button() {
disable_bright_selection(false);
disable_speed_selection(false);
}
} else if (data.mode === 0) {
} else if (state.mode == 0) {
document.getElementById("off").style.backgroundColor = settings.theme_btnsel;
disable_modebuttons(false);
disable_color_selection(true);
@@ -2282,32 +2409,32 @@ function disable_modebuttons(status) {
function set_mode(mode_id) {
if (Number.isInteger(mode_id)) {
data.mode = 1;
data.ws2812fx_mode = mode_id;
state.mode = 1;
segstate.mode = mode_id;
} else {
// For named modes
if (mode_id == "off") {
data.mode = 0;
state.mode = 0;
}
}
select_active_button();
ws_send("/" + mode_id);
}
function set_speed() {
ws_send("?" + data.speed);
ws_send("?" + segstate.speed);
}
function set_brightness() {
ws_send("%" + data.brightness);
ws_send("%" + state.brightness);
}
function set_color() {
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) {
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) {
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 hex_color = rgbToHex(color);
var colnum = (data.color_num === 1) ? "" : data.color_num;
data.color["hex" + colnum] = hex_color;
data.color["r" + colnum] = color[0];
data.color["g" + colnum] = color[1];
data.color["b" + colnum] = color[2];
data.color["w" + colnum] = 0;
segstate.color["hex" + colnum] = hex_color;
segstate.color["r" + colnum] = color[0];
segstate.color["g" + colnum] = color[1];
segstate.color["b" + colnum] = color[2];
segstate.color["w" + colnum] = 0;
red.value = color[0];
green.value = color[1];
blue.value = color[2];
@@ -2357,7 +2484,7 @@ function onSelectColor(event) {
displayColors();
initSliderColors();
changeRangeNumVal();
colorNumrVals();
colorNumVals();
}
}
function redrawColorPicker() {
@@ -2525,13 +2652,11 @@ document.addEventListener("DOMContentLoaded", function(event) {
getModes();
readSettings();
ws_connect();
ws_send("$")
document.getElementById("modal-content").innerHTML = language.en.loadModes;
ws_send("$");
//ws_send("C");
getConfig();
canvas.width = 400;
canvas.height = 400;
redrawColorPicker();
});
</script>
Binary file not shown.