From 4d2cb2016e70df81e4394ce164579a374f19e261 Mon Sep 17 00:00:00 2001 From: Ewowi Date: Tue, 9 Aug 2022 22:44:44 +0200 Subject: [PATCH 1/4] Add weather usermod --- usermods/usermod_v2_weather/readme.md | 10 + .../usermod_v2_weather/usermod_v2_weather.h | 348 ++++++++++++++++++ wled00/FX.h | 2 +- wled00/const.h | 1 + wled00/html_other.h | 92 ++--- wled00/html_settings.h | 282 +++++++------- wled00/usermods_list.cpp | 8 + 7 files changed, 555 insertions(+), 188 deletions(-) create mode 100644 usermods/usermod_v2_weather/readme.md create mode 100644 usermods/usermod_v2_weather/usermod_v2_weather.h diff --git a/usermods/usermod_v2_weather/readme.md b/usermods/usermod_v2_weather/readme.md new file mode 100644 index 00000000..8917a1fb --- /dev/null +++ b/usermods/usermod_v2_weather/readme.md @@ -0,0 +1,10 @@ +# Usermods API v2 example usermod + +In this usermod file you can find the documentation on how to take advantage of the new version 2 usermods! + +## Installation + +Copy `usermod_v2_example.h` to the wled00 directory. +Uncomment the corresponding lines in `usermods_list.cpp` and compile! +_(You shouldn't need to actually install this, it does nothing useful)_ + diff --git a/usermods/usermod_v2_weather/usermod_v2_weather.h b/usermods/usermod_v2_weather/usermod_v2_weather.h new file mode 100644 index 00000000..6927dcc7 --- /dev/null +++ b/usermods/usermod_v2_weather/usermod_v2_weather.h @@ -0,0 +1,348 @@ +#pragma once + +#include "wled.h" + +#define FX_MODE_2DWEATHER 185 // can we do this here? Can we also increase modeCount here? + +#define pushLoopIndex 0 +#define tempsIndex 1 +#define timesIndex 2 +#define minTempIndex 3 +#define maxTempIndex 4 + +//utility function, move somewhere else??? +void epochToString(time_t time, char *timeString) { + tmElements_t tm; + breakTime(time, tm); + sprintf(timeString, "%04d-%02d-%02d %02d:%02d:%02d", tm.Year + 1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second); +} + +//effect function +uint16_t mode_2DWeather(void) { + //or use um_data or make vars global static ...??? Looking at the amount of extra code, global static cleaner? + um_data_t *um_data; + if (!usermods.getUMData(&um_data, USERMOD_ID_WEATHER)) { + SEGMENT.fill(SEGCOLOR(0)); + return FRAMETIME; + } + uint32_t *pushLoop = (uint32_t*)um_data->u_data[pushLoopIndex]; //pointer as it is set here + float *temps = (float*)um_data->u_data[tempsIndex]; + time_t *times = (time_t*)um_data->u_data[timesIndex]; + float minTemp = *(float*)um_data->u_data[minTempIndex]; + float maxTemp = *(float*)um_data->u_data[maxTempIndex]; + + *pushLoop = millis(); //will be reset to 0 in usermod loop + + SEGMENT.fadeToBlackBy(10); + + float currentTemp = 0; + // time_t currentTime = 0; + + for (int x=0; x= localTime) { + color = RED; + currentTemp = map(localTime, times[x%100], times[(x+1)%100], temps[x%100] * 1000, temps[(x+1)%100] * 1000) / 1000.0; + // currentTime = localTime; + } + else + color = ColorFromPalette(SEGPALETTE, map((uint8_t)temps[x%100], 0, 40, 0, 255), 255, LINEARBLEND); + + for (int y=0; yu_size = 5; + um_data->u_type = new um_types_t[um_data->u_size]; + um_data->u_data = new void*[um_data->u_size]; + um_data->u_data[pushLoopIndex] = &pushLoop; + um_data->u_type[pushLoopIndex] = UMT_UINT32; + um_data->u_data[tempsIndex] = temps; + um_data->u_type[tempsIndex] = UMT_FLOAT_ARR; + um_data->u_data[timesIndex] = times; + um_data->u_type[timesIndex] = UMT_UINT32_ARR; + um_data->u_data[minTempIndex] = &minTemp; + um_data->u_type[minTempIndex] = UMT_FLOAT; + um_data->u_data[maxTempIndex] = &maxTemp; + um_data->u_type[maxTempIndex] = UMT_FLOAT; + + strip.addEffect(FX_MODE_2DWEATHER, &mode_2DWeather, _data_FX_MODE_2DWEATHER); + } + + void connected() { + } + + void loop() { + //execute only if effect pushes it or every hour + if (pushLoop > millis() - 1000 && (lastTime == 0 || millis() - lastTime > 3600 * 1000)) { + lastTime = millis(); + + //https://arduinojson.org/v6/example/http-client/ + //is this the most compact way to do http get and put it in arduinojson object??? + WiFiClient client; + + client.setTimeout(10000); + if (!client.connect("api.openweathermap.org", 80)) { + Serial.println(F("Connection failed")); + return; + } + + Serial.println(F("Connected!")); + + char url[180]; + sprintf(url, "GET /data/2.5/forecast?lat=%f&lon=%f&appid=%s&units=%s HTTP/1.0", latitude, longitude, apiKey.c_str(), units==0?"standard":units==1?"metric":"imperial"); + Serial.println(url); + // Send HTTP request + client.println(url); + client.println(F("Host: api.openweathermap.org")); + client.println(F("Connection: close")); + if (client.println() == 0) { + Serial.println(F("Failed to send request")); + client.stop(); + return; + } + + // Check HTTP status + char status[32] = {0}; + client.readBytesUntil('\r', status, sizeof(status)); + if (strcmp(status, "HTTP/1.1 200 OK") != 0) { + Serial.print(F("Unexpected response: ")); + Serial.println(status); + client.stop(); + return; + } + Serial.println(status); + + // Skip HTTP headers + char endOfHeaders[] = "\r\n\r\n"; + if (!client.find(endOfHeaders)) { + Serial.println(F("Invalid response")); + client.stop(); + return; + } + + // Allocate the JSON document + // Use arduinojson.org/v6/assistant to compute the capacity. + // const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60; + DynamicJsonDocument weatherDoc(20000); + + // Parse JSON object + DeserializationError error = deserializeJson(weatherDoc, client); + if (error) { + Serial.print(F("deserializeJson() failed: ")); + Serial.println(error.f_str()); + client.stop(); + return; + } + + // Disconnect + client.stop(); + + + JsonObject weatherDocObject = weatherDoc.as(); + JsonArray list = weatherDocObject[F("list")]; + + uint8_t i = 0; + for (JsonObject listElement: list) { + JsonObject main = listElement["main"]; + + char timeString[64]; + epochToString(listElement["dt"], timeString); + Serial.print(timeString); + + float temp = main["temp"]; + Serial.print(" temp "); + Serial.print(temp); + + temps[i%100] = temp; + times[i%100] = listElement["dt"]; + + JsonObject city = weatherDocObject["city"]; + Serial.print(" city "); + Serial.print((const char *)city["name"]); + Serial.print(" - "); + Serial.print((const char *)city["country"]); + Serial.print(" sunrise "); + char sunriseString[64]; + epochToString(city["sunrise"], sunriseString); + Serial.print(sunriseString); + + Serial.print(" localtime "); + char localTimeString[64]; + epochToString(localTime, localTimeString); + Serial.print(localTimeString); + + Serial.println(); + i++; + } + } + pushLoop = 0; + } + + bool getUMData(um_data_t **data) //do not forget this or um_data doesn't work!! Can it be moved to superclass? + { + if (!data) return false; // no pointer provided by caller or not enabled -> exit + *data = um_data; + return true; + } + + + /* + * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. + * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. + * Below it is shown how this could be used for e.g. a light sensor + */ + /* + void addToJsonInfo(JsonObject& root) + { + int reading = 20; + //this code adds "u":{"Light":[20," lux"]} to the info object + JsonObject user = root["u"]; + if (user.isNull()) user = root.createNestedObject("u"); + + JsonArray lightArr = user.createNestedArray("Light"); //name + lightArr.add(reading); //value + lightArr.add(" lux"); //unit + } + */ + + + /* + * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). + * Values in the state object may be modified by connected clients + */ + void addToJsonState(JsonObject& root) + { + //root["user0"] = userVar0; + } + + + /* + * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object). + * Values in the state object may be modified by connected clients + */ + void readFromJsonState(JsonObject& root) + { + // userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value + //if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!")); + } + + + void addToConfig(JsonObject& root) + { + JsonObject top = root.createNestedObject(FPSTR(_name)); + top["apiKey"] = apiKey; + top["units"] = units; + top["minTemp"] = minTemp; + top["maxTemp"] = maxTemp; + } + + + bool readFromConfig(JsonObject& root) + { + JsonObject top = root[FPSTR(_name)]; + + bool configComplete = !top.isNull(); + + configComplete &= getJsonValue(top["apiKey"], apiKey); + configComplete &= getJsonValue(top["units"], units); + configComplete &= getJsonValue(top["minTemp"], minTemp); + configComplete &= getJsonValue(top["maxTemp"], maxTemp); + + // * Return true in case the config values returned from Usermod Settings were complete, or false if you'd like WLED to save your defaults to disk (so any missing values are editable in Usermod Settings) + return configComplete; + } + + void appendConfigData() + { + oappend(SET_F("dd=addDropdown('WeatherUserMod','units');")); + oappend(SET_F("addOption(dd,'Kelvin',0);")); + oappend(SET_F("addOption(dd,'Celcius',1);")); + oappend(SET_F("addOption(dd,'Fahrenheit',2);")); + oappend(SET_F("addInfo('WeatherUserMod:units',1,'Set time and location in time settings');")); + oappend(SET_F("addInfo('WeatherUserMod:apiKey',1,'Create acount on openweathermap.org and copy the key');")); + oappend(SET_F("addInfo('WeatherUserMod:minTemp',1,'Reboot if you change apiKey to reload forecast');")); + } + + /* + * handleOverlayDraw() is called just before every show() (LED strip update frame) after effects have set the colors. + * Use this to blank out some LEDs or set them to a different color regardless of the set effect mode. + * Commonly used for custom clocks (Cronixie, 7 segment) + */ + void handleOverlayDraw() + { + //strip.setPixelColor(0, RGBW32(0,0,0,0)) // set the first pixel to black + } + + + /* + * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). + * This could be used in the future for the system to determine whether your usermod is installed. + */ + uint16_t getId() + { + return USERMOD_ID_WEATHER; + } +}; + +// strings to reduce flash memory usage (used more than twice) +const char WeatherUsermod::_name[] PROGMEM = "WeatherUserMod"; diff --git a/wled00/FX.h b/wled00/FX.h index d3c7733c..acc9582b 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -378,7 +378,7 @@ // #define FX_MODE_2DAKEMI 186 // audio enhanced //#define FX_MODE_CUSTOMEFFECT 187 //WLEDSR Custom Effects - #define MODE_COUNT 185 + #define MODE_COUNT 186 #endif typedef enum mapping1D2D { diff --git a/wled00/const.h b/wled00/const.h index 499724c4..09404cd9 100644 --- a/wled00/const.h +++ b/wled00/const.h @@ -80,6 +80,7 @@ #define USERMOD_ID_SI7021_MQTT_HA 29 //Usermod "usermod_si7021_mqtt_ha.h" #define USERMOD_ID_BME280 30 //Usermod "usermod_bme280.h #define USERMOD_ID_AUDIOREACTIVE 31 //Usermod "audioreactive.h" +#define USERMOD_ID_WEATHER 32 //Usermod "usermod_v2_weather.h" //Access point behavior #define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot diff --git a/wled00/html_other.h b/wled00/html_other.h index 41c5588b..115fdb98 100644 --- a/wled00/html_other.h +++ b/wled00/html_other.h @@ -282,60 +282,60 @@ const uint8_t PAGE_liveviewws[] PROGMEM = { // Autogenerated from wled00/data/liveviewws2D.htm, do not edit!! -const uint16_t PAGE_liveviewws2D_length = 822; +const uint16_t PAGE_liveviewws2D_length = 828; const uint8_t PAGE_liveviewws2D[] PROGMEM = { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x6d, 0x54, 0x6d, 0x6f, 0xdb, 0x36, 0x10, 0xfe, 0xee, 0x5f, 0xa1, 0x70, 0x43, 0x2b, 0xda, 0x8a, 0xe4, 0xb8, 0xed, 0x96, 0xd9, 0xa2, 0x8b, 0x36, 0x35, 0xb0, 0x02, 0xe9, 0x6a, 0xc0, 0xd9, 0x82, 0x21, 0x30, 0x50, 0x5a, 0x3a, 0x5b, 0x5c, 0x25, 0xd2, 0xa0, 0xce, 0x96, 0x35, 0x47, 0xff, 0xbd, 0x47, 0xc9, 0xf1, 0xb2, 0x75, 0xfa, - 0x40, 0x8a, 0x77, 0xcf, 0x3d, 0x77, 0xbc, 0x17, 0xc6, 0x17, 0x1f, 0x3e, 0xdf, 0xdc, 0xfd, 0x39, + 0x40, 0x8a, 0xf7, 0xf2, 0xdc, 0xf1, 0xb9, 0x3b, 0xc6, 0x17, 0x1f, 0x3e, 0xdf, 0xdc, 0xfd, 0x39, 0x9f, 0x79, 0x19, 0x16, 0xf9, 0x34, 0x3e, 0xad, 0x20, 0xd3, 0x69, 0x5c, 0x00, 0x4a, 0x4f, 0xcb, 0x02, 0x04, 0xdb, 0x2b, 0xa8, 0xb6, 0xc6, 0x22, 0xf3, 0x7a, 0x89, 0xd1, 0x08, 0x1a, 0x05, 0xab, 0x54, 0x8a, 0x99, 0x48, 0x61, 0xaf, 0x12, 0xb8, 0x6c, 0x0f, 0x81, 0xd2, 0x0a, 0x95, 0xcc, 0x2f, - 0xcb, 0x44, 0xe6, 0x20, 0xae, 0x82, 0x82, 0x04, 0xc5, 0xae, 0x78, 0x3a, 0xb3, 0x13, 0x67, 0x2f, - 0xc9, 0xa4, 0x2d, 0x81, 0x38, 0x76, 0xb8, 0xbe, 0xbc, 0x66, 0xff, 0x72, 0x85, 0x19, 0x14, 0x70, - 0x99, 0x98, 0xdc, 0x58, 0xe6, 0x9d, 0x9d, 0xfd, 0x30, 0x6a, 0x3f, 0x82, 0xa2, 0xc2, 0x1c, 0xa6, - 0xbd, 0xfb, 0xdb, 0xd9, 0x07, 0xef, 0x56, 0xed, 0xc1, 0x9b, 0x5b, 0x70, 0xe1, 0xc5, 0x51, 0xa7, - 0x89, 0x4b, 0xac, 0x69, 0x5b, 0x99, 0xb4, 0x3e, 0x16, 0xd2, 0x6e, 0x94, 0x1e, 0x0f, 0x9b, 0x38, - 0xea, 0xa4, 0x71, 0xd4, 0x5d, 0xcd, 0x69, 0xa7, 0x71, 0x22, 0xf5, 0x5e, 0x96, 0x5e, 0x4f, 0xa5, - 0x82, 0xe5, 0x44, 0xe5, 0x68, 0x6e, 0x5a, 0x19, 0x9b, 0x3a, 0xea, 0x3f, 0x5a, 0xda, 0x0e, 0x45, - 0xbc, 0x89, 0x55, 0x5b, 0x9c, 0xf6, 0xf6, 0xd2, 0x7a, 0x89, 0x48, 0x4d, 0xb2, 0x2b, 0x28, 0xb4, - 0x70, 0x03, 0x38, 0xcb, 0xc1, 0xfd, 0xbe, 0xaf, 0x3f, 0xa6, 0xfe, 0x7f, 0x89, 0x78, 0x90, 0x43, - 0x5a, 0x0a, 0xc6, 0x02, 0xcc, 0xac, 0x41, 0x8a, 0x30, 0x15, 0x17, 0x57, 0x93, 0xf5, 0x4e, 0x27, - 0xa8, 0x8c, 0xf6, 0x28, 0x0d, 0x1d, 0xd2, 0xe7, 0xc7, 0x24, 0xec, 0x72, 0x1a, 0xfe, 0x72, 0xdd, - 0xaf, 0x94, 0x4e, 0x4d, 0x15, 0x2a, 0xad, 0xc1, 0xde, 0xb7, 0xc9, 0x4d, 0xc2, 0x0c, 0xd4, 0x26, - 0xc3, 0xef, 0xd4, 0xbf, 0xb6, 0xe2, 0xe6, 0x19, 0xd3, 0xa4, 0x8d, 0x11, 0x0f, 0x22, 0x71, 0xe1, - 0xdd, 0xb8, 0x24, 0x1e, 0xd0, 0x67, 0xa3, 0x94, 0xf1, 0x89, 0x5a, 0xfb, 0xa4, 0xe1, 0x47, 0x07, - 0xa9, 0xca, 0x09, 0xda, 0xfa, 0x58, 0x95, 0x02, 0xcd, 0x36, 0x3c, 0x71, 0x56, 0x65, 0x93, 0x48, - 0x4c, 0x32, 0x1f, 0xf9, 0xb1, 0xa9, 0xca, 0x17, 0x2f, 0xaa, 0x32, 0xb4, 0x94, 0xb5, 0x7a, 0x81, - 0x12, 0x41, 0x08, 0x71, 0x0f, 0xab, 0x85, 0x49, 0xbe, 0x02, 0x86, 0x9f, 0xe7, 0xb3, 0xdf, 0xde, - 0x92, 0xba, 0x04, 0x4d, 0x37, 0x3f, 0xbe, 0xcc, 0xf7, 0x2f, 0xc7, 0x68, 0x77, 0xd0, 0x30, 0x3e, - 0xf6, 0x89, 0x55, 0x43, 0xe5, 0x9d, 0xd1, 0xbe, 0xcf, 0x32, 0xc4, 0x6d, 0x39, 0x66, 0x42, 0x9c, - 0x5c, 0xe5, 0x86, 0x3c, 0x51, 0x16, 0xc2, 0x2d, 0xa5, 0xc6, 0x50, 0xcd, 0xdf, 0xb2, 0xaa, 0x2c, - 0xd9, 0x98, 0x56, 0xc6, 0x07, 0x6c, 0x1c, 0x45, 0x6c, 0x70, 0x4e, 0xf4, 0x19, 0x9c, 0x99, 0x12, - 0x07, 0x2c, 0x72, 0x18, 0x1e, 0x1a, 0x6d, 0xb6, 0xa0, 0x85, 0xcf, 0xc5, 0xf4, 0xf8, 0xff, 0x91, - 0x34, 0x01, 0xc9, 0x57, 0x4a, 0x4b, 0x5b, 0xdf, 0xd5, 0x5b, 0xea, 0x30, 0x69, 0xad, 0xac, 0x57, - 0xbb, 0xf5, 0x1a, 0x2c, 0x73, 0x3a, 0x99, 0xa6, 0xb3, 0x3d, 0x79, 0xb8, 0x55, 0x25, 0x35, 0x1b, - 0x58, 0x9f, 0x15, 0x50, 0x96, 0x72, 0x03, 0x54, 0x33, 0x62, 0x75, 0x19, 0xa2, 0xa4, 0xb1, 0x07, - 0xb3, 0xfa, 0x0b, 0x12, 0xf4, 0xde, 0x39, 0xf3, 0xf7, 0xad, 0xf9, 0x92, 0xae, 0x42, 0xa9, 0x5b, - 0xa0, 0x55, 0x7a, 0x13, 0x52, 0x93, 0xe7, 0x3e, 0x86, 0xa9, 0x44, 0xc9, 0xf9, 0x31, 0x07, 0xf4, - 0xb0, 0xcd, 0xc0, 0xef, 0x4a, 0xe3, 0x75, 0x6b, 0xe5, 0x83, 0xf3, 0xd3, 0x21, 0x5c, 0x21, 0x7e, - 0xfe, 0xe9, 0x42, 0xe0, 0xc3, 0x70, 0xf9, 0xf8, 0x78, 0xe1, 0x6a, 0x62, 0x01, 0x77, 0x56, 0x4f, - 0x9c, 0xa5, 0x25, 0xf9, 0x68, 0x19, 0x68, 0xda, 0x5e, 0x2d, 0x03, 0x23, 0x3e, 0x49, 0xcc, 0x42, - 0x1a, 0x27, 0xff, 0xd4, 0x23, 0x91, 0x3d, 0xf7, 0x43, 0xa4, 0x79, 0x20, 0x3b, 0xc0, 0x3a, 0x37, - 0xc6, 0xfa, 0x4f, 0x98, 0x4b, 0xd3, 0xb7, 0x3c, 0x1a, 0x75, 0xdd, 0x00, 0xe2, 0xf5, 0x64, 0x4d, - 0xca, 0x5a, 0x84, 0x6f, 0x26, 0x75, 0xac, 0x27, 0xf5, 0x60, 0xc0, 0x9d, 0xe0, 0xe0, 0x04, 0x87, - 0xd8, 0x4e, 0x0e, 0x24, 0xa0, 0x28, 0xc2, 0xb5, 0xca, 0xf3, 0x85, 0x9b, 0x16, 0xf1, 0xc5, 0x6e, - 0x56, 0xfe, 0x8f, 0x47, 0x7c, 0x80, 0x65, 0x13, 0xb4, 0xfb, 0xe0, 0xea, 0xfc, 0x37, 0x5a, 0x36, - 0xfc, 0x4b, 0xe0, 0x0c, 0x56, 0x40, 0x43, 0x36, 0x27, 0xff, 0x3e, 0x6f, 0xcf, 0xd2, 0x26, 0xfe, - 0xa1, 0x6f, 0x06, 0x32, 0xa8, 0xfb, 0x26, 0x08, 0x5f, 0xd3, 0x32, 0x0c, 0x46, 0xfd, 0x36, 0xc2, - 0xf9, 0xc7, 0x0e, 0xe3, 0x9c, 0x10, 0x1c, 0x06, 0xe2, 0x55, 0xf3, 0x4f, 0xbb, 0xd1, 0xb8, 0x97, - 0x26, 0x87, 0x10, 0xac, 0xa5, 0xc8, 0xd8, 0x1c, 0xe0, 0xab, 0x77, 0xbf, 0xf0, 0xda, 0xe3, 0x98, - 0xaa, 0xc1, 0x9b, 0x86, 0x37, 0xa7, 0xde, 0xf9, 0xbe, 0x6a, 0x16, 0x4a, 0xf5, 0xf7, 0x53, 0xd1, - 0x9e, 0x86, 0xed, 0xf1, 0xd1, 0x7f, 0x36, 0x18, 0xcf, 0x87, 0x70, 0x18, 0x90, 0xe2, 0x4e, 0x15, - 0x60, 0x76, 0xd4, 0x9b, 0xfc, 0xb9, 0x11, 0x4d, 0x68, 0x13, 0x8c, 0xde, 0x0c, 0x39, 0x6f, 0x78, - 0x8f, 0xde, 0x8e, 0x6e, 0xf2, 0xe3, 0xa8, 0x7b, 0x36, 0xa2, 0xf6, 0x91, 0xfc, 0x06, 0x24, 0x61, - 0xea, 0x04, 0x3a, 0x05, 0x00, 0x00 + 0xcb, 0x44, 0xe6, 0x20, 0xae, 0x82, 0x82, 0x04, 0xc5, 0xae, 0x78, 0x3a, 0xb3, 0x13, 0x66, 0x2f, + 0xc9, 0xa4, 0x2d, 0x81, 0x30, 0x76, 0xb8, 0xbe, 0xbc, 0x66, 0xff, 0x0a, 0x85, 0x19, 0x14, 0x70, + 0x99, 0x98, 0xdc, 0x58, 0xe6, 0x9d, 0x83, 0xfd, 0x30, 0x6a, 0x3f, 0x32, 0x45, 0x85, 0x39, 0x4c, + 0x7b, 0xf7, 0xb7, 0xb3, 0x0f, 0xde, 0xad, 0xda, 0x83, 0x37, 0xb7, 0xe0, 0xd2, 0x8b, 0xa3, 0x4e, + 0x13, 0x97, 0x58, 0xd3, 0xb6, 0x32, 0x69, 0x7d, 0x2c, 0xa4, 0xdd, 0x28, 0x3d, 0x1e, 0x36, 0x71, + 0xd4, 0x49, 0xe3, 0xa8, 0xbb, 0x9a, 0xd3, 0x4e, 0xe3, 0x44, 0xea, 0xbd, 0x2c, 0xbd, 0x9e, 0x4a, + 0x05, 0xcb, 0x09, 0xca, 0xc1, 0xdc, 0xb4, 0x32, 0x36, 0x75, 0xd0, 0x7f, 0xb4, 0xb0, 0x9d, 0x15, + 0xe1, 0x26, 0x56, 0x6d, 0x71, 0xda, 0xdb, 0x4b, 0xeb, 0x25, 0x22, 0x35, 0xc9, 0xae, 0xa0, 0xd4, + 0xc2, 0x0d, 0xe0, 0x2c, 0x07, 0xf7, 0xfb, 0xbe, 0xfe, 0x98, 0xfa, 0xff, 0x05, 0xe2, 0x41, 0x0e, + 0x69, 0x29, 0x18, 0x0b, 0x30, 0xb3, 0x06, 0x29, 0xc3, 0x54, 0x5c, 0x5c, 0x4d, 0xd6, 0x3b, 0x9d, + 0xa0, 0x32, 0xda, 0x23, 0x1a, 0x3a, 0x4b, 0x9f, 0x1f, 0x93, 0xb0, 0xe3, 0x34, 0xfc, 0xe5, 0xba, + 0x5f, 0x29, 0x9d, 0x9a, 0x2a, 0x54, 0x5a, 0x83, 0xbd, 0x6f, 0xc9, 0x4d, 0xc2, 0x0c, 0xd4, 0x26, + 0xc3, 0xef, 0xd4, 0xbf, 0xb6, 0xe2, 0xe6, 0x19, 0xd2, 0xa4, 0xcd, 0x11, 0x0f, 0x22, 0x71, 0xe9, + 0xdd, 0x38, 0x12, 0x0f, 0xe8, 0xb3, 0x51, 0xca, 0xf8, 0x44, 0xad, 0x7d, 0xd2, 0xf0, 0xa3, 0x33, + 0xa9, 0xca, 0x09, 0xda, 0xfa, 0x58, 0x95, 0x02, 0xcd, 0x36, 0x3c, 0x61, 0x56, 0x65, 0x93, 0x48, + 0x4c, 0x32, 0x1f, 0xf9, 0xb1, 0xa9, 0xca, 0x17, 0x2f, 0xaa, 0x32, 0xb4, 0xc4, 0x5a, 0xbd, 0x40, + 0x89, 0x20, 0x84, 0xb8, 0x87, 0xd5, 0xc2, 0x24, 0x5f, 0x01, 0xc3, 0xcf, 0xf3, 0xd9, 0x6f, 0x6f, + 0x49, 0x5d, 0x82, 0xa6, 0x9b, 0x1f, 0x5f, 0xe6, 0xfb, 0x97, 0x63, 0xb4, 0x3b, 0x68, 0x18, 0x1f, + 0xfb, 0x84, 0xaa, 0xa1, 0xf2, 0xce, 0xd6, 0xbe, 0xcf, 0x32, 0xc4, 0x6d, 0x39, 0x66, 0x42, 0x9c, + 0x42, 0xe5, 0x86, 0x22, 0x11, 0x0b, 0xe1, 0x96, 0xa8, 0x31, 0x54, 0xf3, 0xb7, 0xac, 0x2a, 0x4b, + 0x36, 0xa6, 0x95, 0xf1, 0x01, 0x1b, 0x47, 0x11, 0x1b, 0x9c, 0x89, 0x3e, 0x1b, 0x67, 0xa6, 0xc4, + 0x01, 0x8b, 0x9c, 0x0d, 0x0f, 0x8d, 0x36, 0x5b, 0xd0, 0xc2, 0xe7, 0x62, 0x7a, 0xfc, 0xff, 0x4c, + 0x9a, 0x80, 0xe4, 0x2b, 0xa5, 0xa5, 0xad, 0xef, 0xea, 0x2d, 0x75, 0x98, 0xb4, 0x56, 0xd6, 0xab, + 0xdd, 0x7a, 0x0d, 0x96, 0x39, 0x9d, 0x4c, 0xd3, 0xd9, 0x9e, 0x22, 0xdc, 0xaa, 0x92, 0x9a, 0x0d, + 0xac, 0xcf, 0x0a, 0x28, 0x4b, 0xb9, 0x01, 0xaa, 0x19, 0xa1, 0x3a, 0x86, 0x88, 0x34, 0xf6, 0x60, + 0x56, 0x7f, 0x41, 0x82, 0xde, 0x3b, 0xe7, 0xfe, 0xbe, 0x75, 0x5f, 0xd2, 0x55, 0x88, 0xba, 0x05, + 0x5a, 0xa5, 0x37, 0x21, 0x35, 0x79, 0xee, 0x63, 0x98, 0x4a, 0x94, 0x9c, 0x1f, 0x73, 0x40, 0x0f, + 0x5b, 0x06, 0x7e, 0x57, 0x1a, 0xaf, 0x5b, 0x2f, 0x1f, 0x5c, 0x9c, 0xce, 0xc2, 0x15, 0xe2, 0xe7, + 0x9f, 0x2e, 0x04, 0x3e, 0x0c, 0x97, 0x8f, 0x8f, 0x17, 0xae, 0x26, 0x16, 0x70, 0x67, 0xf5, 0xc4, + 0x79, 0x5a, 0x92, 0x8f, 0x96, 0x81, 0xa6, 0xed, 0xd5, 0x32, 0x30, 0xe2, 0x93, 0xc4, 0x2c, 0xa4, + 0x71, 0xf2, 0x4f, 0x3d, 0x12, 0xd9, 0x73, 0x3f, 0x44, 0x9a, 0x4f, 0x6c, 0x5f, 0x98, 0x40, 0xd3, + 0xd2, 0x3a, 0xcb, 0xce, 0x7c, 0x9d, 0x1b, 0x63, 0xfd, 0x27, 0x8f, 0x4b, 0xcb, 0xa3, 0x51, 0xd7, + 0x19, 0x20, 0x5e, 0x4f, 0xd6, 0xa4, 0xaa, 0x45, 0xf8, 0xa6, 0x6f, 0x26, 0x75, 0xac, 0x27, 0xf5, + 0x40, 0x18, 0xee, 0x64, 0x87, 0x4e, 0x76, 0x88, 0xed, 0xe4, 0xe0, 0x64, 0x94, 0x57, 0xb8, 0x56, + 0x79, 0xbe, 0x70, 0xf3, 0x23, 0xbe, 0xd8, 0xcd, 0xca, 0xff, 0xf1, 0x88, 0x0f, 0xb0, 0x6c, 0x82, + 0x76, 0x1f, 0x5c, 0x9d, 0xff, 0x46, 0xcb, 0x86, 0x7f, 0x09, 0x9c, 0xc3, 0x0a, 0x68, 0xec, 0xe6, + 0x94, 0x83, 0xcf, 0xdb, 0xb3, 0xb4, 0x89, 0x7f, 0x18, 0xc8, 0xa0, 0x0e, 0xc2, 0xd7, 0x7d, 0x13, + 0x0c, 0x83, 0x51, 0xbf, 0xcd, 0x70, 0xfe, 0xb1, 0xd3, 0xbb, 0x00, 0x64, 0x0a, 0x03, 0xf1, 0xaa, + 0xf9, 0xa7, 0xf9, 0x68, 0xf8, 0x4b, 0x93, 0x43, 0x08, 0xd6, 0x52, 0x62, 0x6c, 0x0e, 0xf0, 0xd5, + 0xbb, 0x5f, 0x78, 0xed, 0x71, 0x4c, 0xb5, 0xe1, 0x4d, 0xc3, 0x9b, 0x53, 0x27, 0x7d, 0x5f, 0x43, + 0x0b, 0xa5, 0xfa, 0xfb, 0xa9, 0x84, 0x4f, 0xa3, 0xf7, 0xf8, 0xe8, 0x3f, 0x1b, 0x93, 0xe7, 0x23, + 0x39, 0x0c, 0x48, 0x71, 0xa7, 0x0a, 0x30, 0x3b, 0xea, 0x54, 0xfe, 0xdc, 0x89, 0xe6, 0xb5, 0x09, + 0x46, 0x6f, 0x86, 0x9c, 0x37, 0xbc, 0x47, 0x2f, 0x49, 0xf7, 0x0e, 0xc4, 0x51, 0xf7, 0x88, 0x44, + 0xed, 0x93, 0xf9, 0x0d, 0x93, 0x14, 0x9e, 0x90, 0x48, 0x05, 0x00, 0x00 }; diff --git a/wled00/html_settings.h b/wled00/html_settings.h index 99f3ab86..2e9f3d1a 100644 --- a/wled00/html_settings.h +++ b/wled00/html_settings.h @@ -1582,148 +1582,148 @@ const uint8_t PAGE_settings_sec[] PROGMEM = { // Autogenerated from wled00/data/settings_um.htm, do not edit!! -const uint16_t PAGE_settings_um_length = 2230; +const uint16_t PAGE_settings_um_length = 2239; const uint8_t PAGE_settings_um[] PROGMEM = { - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0xa5, 0x58, 0x6d, 0x53, 0xdb, 0x48, - 0x12, 0xfe, 0xce, 0xaf, 0x10, 0x13, 0x0a, 0xa4, 0xb2, 0x90, 0x4d, 0xb8, 0xdd, 0x4b, 0x6c, 0x8f, - 0xd9, 0x90, 0x97, 0x0b, 0x57, 0x49, 0xa0, 0x8a, 0xec, 0x5e, 0x5d, 0x71, 0xd4, 0x22, 0x4b, 0x63, - 0x7b, 0x82, 0x3c, 0xa3, 0x9a, 0x19, 0xf1, 0x72, 0xc6, 0xff, 0xfd, 0x9e, 0x1e, 0x49, 0xc6, 0x26, - 0x64, 0xf7, 0xae, 0xee, 0x0b, 0xa0, 0x51, 0x4f, 0xab, 0xe7, 0xe9, 0xa7, 0x9f, 0xee, 0x61, 0xb8, - 0xfd, 0xee, 0xf4, 0xed, 0xd7, 0x7f, 0x9e, 0xbd, 0x0f, 0x66, 0x6e, 0x5e, 0x8c, 0x86, 0xcd, 0x4f, - 0x91, 0xe6, 0x41, 0x91, 0xaa, 0x29, 0x67, 0x42, 0xb1, 0xd1, 0x70, 0x2e, 0x5c, 0x1a, 0x64, 0xb3, - 0xd4, 0x58, 0xe1, 0x38, 0xab, 0xdc, 0x64, 0xff, 0x55, 0xbb, 0xba, 0xa5, 0xd2, 0xb9, 0xe0, 0xec, - 0x46, 0x8a, 0xdb, 0x52, 0x1b, 0xc7, 0x82, 0x4c, 0x2b, 0x27, 0x14, 0xcc, 0x6e, 0x65, 0xee, 0x66, - 0xfc, 0xa7, 0x5e, 0x6f, 0x65, 0xfa, 0xe4, 0x55, 0x2e, 0x6e, 0x64, 0x26, 0xf6, 0xfd, 0x43, 0x2c, - 0x95, 0x74, 0x32, 0x2d, 0xf6, 0x6d, 0x96, 0x16, 0x82, 0x1f, 0xc4, 0xf3, 0xf4, 0x4e, 0xce, 0xab, - 0xf9, 0xea, 0xb9, 0xb2, 0xc2, 0xf8, 0x87, 0x74, 0x8c, 0x67, 0xa5, 0xd9, 0x77, 0x5f, 0x1e, 0x0d, - 0x9d, 0x74, 0x85, 0x18, 0xfd, 0x0a, 0xcb, 0xb9, 0xce, 0x83, 0x73, 0xe1, 0x9c, 0x54, 0x53, 0x3b, - 0xec, 0xd6, 0xeb, 0x43, 0x9b, 0x19, 0x59, 0xba, 0xd1, 0xd6, 0x4d, 0x6a, 0x02, 0x7d, 0xab, 0x84, - 0x89, 0x0b, 0x9d, 0xc9, 0x32, 0xae, 0x8c, 0xbe, 0xb5, 0x71, 0xce, 0x73, 0x9d, 0x55, 0x73, 0xc4, - 0x17, 0x57, 0xf3, 0xb7, 0x93, 0x29, 0x5f, 0x2c, 0xe3, 0x52, 0x2a, 0xcb, 0x2f, 0x7e, 0x8e, 0xff, - 0x1a, 0xbf, 0x8a, 0x5f, 0xc7, 0x07, 0xbd, 0xf8, 0xe0, 0xe0, 0x92, 0x16, 0x4f, 0xf9, 0x05, 0x33, - 0xf6, 0x26, 0x67, 0xf1, 0x9f, 0xff, 0xba, 0xa4, 0xaf, 0xf0, 0xed, 0x83, 0x58, 0x55, 0xf3, 0xcf, - 0xbc, 0x37, 0x98, 0x54, 0x2a, 0x73, 0x52, 0xab, 0x60, 0x7a, 0x92, 0x87, 0x22, 0x5a, 0x18, 0xe1, - 0x2a, 0xa3, 0x82, 0x3c, 0x99, 0x0a, 0xf7, 0xbe, 0x10, 0x14, 0xc0, 0xf1, 0xbd, 0x7f, 0xb5, 0x5c, - 0x99, 0x4a, 0x7b, 0xba, 0x66, 0x2a, 0x76, 0x77, 0x99, 0x1e, 0x7f, 0x13, 0x99, 0x63, 0x9c, 0xbb, - 0xfb, 0x52, 0xe8, 0x09, 0xad, 0x6d, 0xbf, 0x31, 0x26, 0xbd, 0x4f, 0xa4, 0xf5, 0xbf, 0x37, 0xf6, - 0x7f, 0x0c, 0xa3, 0xc5, 0xad, 0x54, 0xb9, 0xbe, 0x4d, 0x74, 0x29, 0x54, 0xc8, 0x66, 0xce, 0x95, - 0xb6, 0xdf, 0xed, 0x4e, 0xa5, 0x9b, 0x55, 0xe3, 0x24, 0xd3, 0xf3, 0xee, 0x1b, 0x69, 0x32, 0xad, - 0xf5, 0xb5, 0x14, 0xdd, 0x7f, 0x7c, 0x7a, 0xff, 0xae, 0x7b, 0x2b, 0xaf, 0x65, 0xb7, 0xc5, 0xf0, - 0x45, 0x55, 0x83, 0xba, 0x6f, 0x9b, 0x05, 0xb6, 0xe6, 0xfd, 0xf8, 0xa9, 0xf7, 0xee, 0xca, 0x2a, - 0x66, 0xbf, 0x5b, 0x51, 0x4c, 0xd6, 0xad, 0x0b, 0x9d, 0xe6, 0x7f, 0x3f, 0x0f, 0x45, 0xec, 0xf8, - 0x76, 0x2f, 0x5a, 0x14, 0xc2, 0x05, 0x8a, 0xe7, 0x49, 0x66, 0x44, 0xea, 0x44, 0x03, 0x40, 0xc8, - 0xea, 0x5c, 0xb1, 0x68, 0xa0, 0x12, 0x38, 0x7b, 0xe3, 0x9c, 0x91, 0xe3, 0xca, 0x09, 0xbc, 0x30, - 0x19, 0x8b, 0x45, 0x14, 0x3f, 0x5d, 0x27, 0x1c, 0xf0, 0x39, 0x27, 0xee, 0x5c, 0xf7, 0x5b, 0x7a, - 0x93, 0xb6, 0x0e, 0xbe, 0x33, 0x4c, 0xed, 0xbd, 0x82, 0x0b, 0x17, 0xc5, 0x79, 0x32, 0xd6, 0xf9, - 0x7d, 0x92, 0x96, 0x08, 0x3a, 0x7f, 0x3b, 0x93, 0x45, 0x1e, 0x2a, 0xb2, 0x4f, 0xf3, 0xfc, 0xfd, - 0x0d, 0xa2, 0xf8, 0x24, 0x2d, 0xe8, 0x2a, 0x4c, 0xc8, 0x28, 0x66, 0x16, 0x87, 0x11, 0x1f, 0x2d, - 0xfe, 0x26, 0xdc, 0x6f, 0x61, 0xb4, 0x7c, 0xde, 0x4e, 0x18, 0xa3, 0x0d, 0xc2, 0x83, 0x1d, 0xb8, - 0x6e, 0x75, 0x21, 0x92, 0x42, 0x4f, 0x43, 0xf6, 0x9e, 0xd6, 0x83, 0xe6, 0xf0, 0x00, 0x26, 0x98, - 0xc8, 0x42, 0xf8, 0x63, 0x80, 0xdc, 0x06, 0xc7, 0xfd, 0xd4, 0xac, 0x23, 0x93, 0xd8, 0x38, 0x91, - 0xd3, 0xca, 0xa4, 0x1e, 0xad, 0xfa, 0x18, 0xc1, 0x24, 0xc5, 0x86, 0x3c, 0xf9, 0x97, 0x3a, 0x51, - 0xc8, 0x55, 0x09, 0xd0, 0x44, 0x50, 0xa6, 0x53, 0x11, 0xe4, 0xa9, 0x4b, 0xb7, 0x01, 0xef, 0x1a, - 0xc0, 0xe7, 0x48, 0x07, 0xa3, 0x0f, 0xf4, 0x41, 0x8f, 0x26, 0x2f, 0xa0, 0xa0, 0xf7, 0x97, 0x94, - 0x46, 0x3b, 0x9d, 0xe9, 0x62, 0x77, 0x37, 0xf4, 0xb4, 0xec, 0xc5, 0xa1, 0x2f, 0x02, 0x4e, 0x16, - 0xc5, 0xb9, 0xd3, 0x06, 0x5e, 0x89, 0x8a, 0x27, 0x4e, 0xcc, 0xe9, 0xe0, 0xd9, 0x49, 0xc9, 0xa2, - 0xe8, 0xe1, 0xa1, 0x31, 0xc3, 0xfe, 0x79, 0x89, 0x80, 0x3f, 0xc0, 0x7f, 0xf0, 0x59, 0xe7, 0x22, - 0x09, 0xce, 0x0a, 0x91, 0x5a, 0x11, 0x00, 0x08, 0x61, 0x02, 0xa2, 0x4e, 0x70, 0x72, 0x86, 0x90, - 0xe2, 0x0d, 0x8f, 0x76, 0xd3, 0x63, 0x5d, 0x79, 0x51, 0x04, 0xab, 0x1c, 0xf1, 0xfa, 0xda, 0xc0, - 0x37, 0xa8, 0x24, 0x58, 0x35, 0x67, 0x51, 0x22, 0x15, 0x00, 0xfd, 0xf8, 0xf5, 0xf3, 0x27, 0xce, - 0xbe, 0xe8, 0xa0, 0x29, 0x69, 0x1b, 0xa0, 0x1e, 0x5d, 0x5a, 0x10, 0x14, 0x6c, 0xa3, 0x3c, 0x3e, - 0xac, 0x97, 0x07, 0xe7, 0xbc, 0x83, 0x7a, 0x10, 0xdb, 0x9c, 0x87, 0xbd, 0x87, 0xcd, 0x3a, 0x3a, - 0x79, 0xce, 0x90, 0x7f, 0x67, 0x98, 0xcd, 0x44, 0x76, 0x4d, 0x1c, 0x8d, 0x16, 0xa4, 0x16, 0x8a, - 0x8b, 0x84, 0xd4, 0x26, 0x31, 0xa2, 0x2c, 0xd2, 0x0c, 0x2c, 0xba, 0xb8, 0x04, 0xd9, 0x10, 0xa7, - 0xad, 0xc6, 0xd6, 0x99, 0x70, 0xff, 0x30, 0x1a, 0xc8, 0x49, 0xc8, 0x70, 0x8e, 0xb1, 0x30, 0xc0, - 0x5d, 0x24, 0x44, 0x48, 0x14, 0x2a, 0xd4, 0x02, 0x8f, 0xaa, 0x35, 0xec, 0xc5, 0x87, 0x51, 0x34, - 0xd1, 0x26, 0x24, 0xb7, 0x12, 0x72, 0x20, 0x87, 0x24, 0x32, 0x49, 0x21, 0xd4, 0xd4, 0xcd, 0x06, - 0xb2, 0xd3, 0x89, 0xe0, 0xc7, 0x6d, 0x73, 0x52, 0x99, 0x0b, 0x79, 0x19, 0x2d, 0xf0, 0x28, 0x92, - 0x9b, 0xb4, 0xa8, 0x10, 0x26, 0x99, 0x62, 0xf1, 0xe1, 0xa1, 0x59, 0x19, 0xee, 0x1f, 0xac, 0xfe, - 0x1e, 0x1d, 0xbe, 0x8e, 0x16, 0x00, 0xda, 0xdd, 0x83, 0x75, 0xc8, 0xb0, 0x36, 0x9c, 0x19, 0x91, - 0xb3, 0xc1, 0x18, 0x95, 0x75, 0xbd, 0xdc, 0x7c, 0xb3, 0xda, 0x73, 0x78, 0xc4, 0x90, 0x20, 0x35, - 0x15, 0xac, 0xcf, 0x5e, 0x4c, 0x26, 0x13, 0xb6, 0x7c, 0x04, 0x01, 0x2c, 0x38, 0xc3, 0x07, 0x09, - 0x31, 0x04, 0x51, 0x6b, 0x90, 0x8f, 0x9d, 0xb8, 0xed, 0x2e, 0x54, 0x2c, 0x2f, 0xc1, 0xd7, 0x53, - 0xaf, 0x44, 0x09, 0xd2, 0x6f, 0xa4, 0x20, 0xe3, 0xa8, 0x31, 0x96, 0x51, 0xe4, 0x55, 0x96, 0xab, - 0xb8, 0xf5, 0x24, 0xa3, 0x81, 0x28, 0xc0, 0x15, 0x82, 0xaa, 0x05, 0xe6, 0x0f, 0x20, 0x25, 0x4f, - 0x9b, 0xa2, 0x26, 0x1f, 0xc1, 0x73, 0x00, 0xcf, 0x0d, 0x65, 0x8b, 0x9c, 0x23, 0xe4, 0x2e, 0xdc, - 0xe5, 0x88, 0xf7, 0xc0, 0x6d, 0x8f, 0x69, 0x59, 0xd9, 0x59, 0x48, 0x6b, 0x91, 0xd7, 0xec, 0xfa, - 0xd9, 0x87, 0x14, 0xb5, 0x71, 0x7c, 0x67, 0xfd, 0x63, 0xd3, 0x1f, 0x84, 0xf2, 0x4c, 0x18, 0xab, - 0xd3, 0xd2, 0xa7, 0x1f, 0xe1, 0x84, 0x5c, 0x7c, 0x90, 0x02, 0x22, 0x03, 0x5a, 0xc5, 0x00, 0x0f, - 0x3d, 0x61, 0x05, 0xac, 0x8a, 0xa2, 0x85, 0x6f, 0x43, 0x1d, 0xbe, 0x37, 0x9c, 0x99, 0xc0, 0xe7, - 0xaa, 0xe9, 0x93, 0xfd, 0x97, 0x3f, 0xf7, 0xca, 0x3b, 0x36, 0xda, 0x1b, 0x3c, 0x62, 0x2f, 0x63, - 0xf3, 0x0c, 0xf6, 0xf0, 0xc2, 0x2a, 0x75, 0xad, 0x10, 0x38, 0xa0, 0xe5, 0x8e, 0xb8, 0x21, 0x55, - 0x56, 0x54, 0x39, 0x5e, 0x22, 0xc1, 0xd1, 0xd1, 0x5a, 0x0c, 0x70, 0x11, 0xf5, 0x1f, 0x9f, 0x3b, - 0x78, 0xdf, 0x71, 0x7e, 0x75, 0xf9, 0xfc, 0x81, 0xd5, 0x23, 0xf6, 0x06, 0x87, 0x36, 0x43, 0xd5, - 0x1e, 0xda, 0xe0, 0xd0, 0x9b, 0xa7, 0xbb, 0x30, 0x97, 0x31, 0xd4, 0xdd, 0x43, 0xe7, 0x2b, 0xc8, - 0xc6, 0xba, 0x6d, 0x55, 0x6a, 0x60, 0x6f, 0xa5, 0xcb, 0x80, 0x6f, 0xb4, 0xc8, 0xa0, 0x1c, 0x6c, - 0xac, 0x21, 0x94, 0xa9, 0x62, 0x7d, 0xcd, 0x99, 0x2f, 0xbc, 0xb1, 0xbe, 0x63, 0xb1, 0xe5, 0x7b, - 0x35, 0xeb, 0x99, 0x33, 0x95, 0x60, 0x7b, 0x9d, 0x50, 0x1d, 0xb1, 0xba, 0x30, 0xc1, 0xea, 0x3e, - 0x98, 0x52, 0x33, 0x7b, 0xe0, 0x7d, 0x34, 0x85, 0xd7, 0xb7, 0xfc, 0xaa, 0xd9, 0xb5, 0xb3, 0x50, - 0x4b, 0x76, 0x15, 0x37, 0x3c, 0xe3, 0x6e, 0x8d, 0x57, 0x47, 0x21, 0xe1, 0x1c, 0x60, 0xc4, 0xe0, - 0xec, 0xf0, 0x35, 0x0b, 0xe6, 0x52, 0x71, 0xb6, 0x7f, 0x00, 0xef, 0x45, 0x6a, 0x2d, 0x67, 0x96, - 0xed, 0x21, 0x5c, 0x26, 0x15, 0xfa, 0x47, 0xdf, 0x9b, 0x42, 0xe0, 0x4b, 0xce, 0x52, 0x75, 0xbf, - 0xb2, 0xb9, 0xbb, 0x2b, 0xd8, 0x5e, 0x13, 0x41, 0x2e, 0x26, 0x69, 0x55, 0x38, 0x8a, 0x9f, 0xfa, - 0x0f, 0xc5, 0xbe, 0x11, 0xc5, 0x93, 0x74, 0xfe, 0x84, 0x74, 0x0e, 0xd8, 0xd5, 0xf2, 0x49, 0x72, - 0x40, 0xc4, 0x86, 0x02, 0xa2, 0x8d, 0x95, 0x2c, 0x72, 0x71, 0x77, 0x3a, 0xf1, 0x06, 0x9d, 0x03, - 0xe8, 0x65, 0x63, 0x72, 0x15, 0xec, 0x2c, 0xdc, 0xb2, 0x1f, 0xe0, 0x80, 0x2b, 0xc8, 0x38, 0xd7, - 0x47, 0xed, 0xeb, 0xa1, 0x54, 0x65, 0xe5, 0x02, 0x82, 0x9c, 0xb3, 0x99, 0xcc, 0x73, 0xcc, 0x71, - 0x41, 0x3d, 0x30, 0xed, 0x2c, 0xc4, 0xb2, 0x4f, 0xbb, 0x77, 0x16, 0xf2, 0x88, 0xaa, 0x0e, 0x58, - 0x22, 0xc6, 0x26, 0xe0, 0x49, 0x8a, 0x94, 0xb1, 0xd1, 0x55, 0x5f, 0x42, 0x8f, 0xff, 0x6f, 0x6f, - 0x3b, 0x0b, 0xbd, 0x84, 0xb3, 0xc7, 0xb0, 0x37, 0x3c, 0xed, 0x2c, 0x3c, 0xc6, 0x9c, 0x02, 0x5f, - 0x65, 0x10, 0x1b, 0xfe, 0xd8, 0xf5, 0xce, 0xc2, 0x2e, 0xd1, 0x4b, 0xbd, 0xa3, 0x86, 0x30, 0xa1, - 0x9b, 0x49, 0x1b, 0xef, 0xed, 0x2c, 0x7e, 0x8c, 0xdc, 0x72, 0x2f, 0xc2, 0x84, 0x38, 0x36, 0xa3, - 0xab, 0xe5, 0x46, 0x49, 0xbe, 0x33, 0xba, 0x44, 0x87, 0x54, 0xb5, 0xd8, 0xff, 0x68, 0x1a, 0x11, - 0x05, 0x4d, 0x5b, 0x11, 0x8a, 0x76, 0x7d, 0x4e, 0xb3, 0xc7, 0xf7, 0x5f, 0x10, 0x69, 0x5b, 0x3c, - 0xd1, 0xc5, 0xc1, 0x25, 0x75, 0x01, 0x09, 0xd9, 0x3f, 0xf9, 0x72, 0xf6, 0xeb, 0x57, 0x3a, 0x99, - 0x4c, 0x5c, 0x3a, 0x25, 0x2b, 0xa4, 0xb7, 0x66, 0x47, 0xbd, 0x08, 0x00, 0x1e, 0x1e, 0x1e, 0xfb, - 0x45, 0xb3, 0x14, 0xd5, 0x21, 0x08, 0x3c, 0x7a, 0x04, 0x07, 0xd2, 0xf7, 0x9d, 0xc1, 0x66, 0xe1, - 0xc9, 0x24, 0x6d, 0xe7, 0x99, 0x55, 0xe7, 0xe8, 0x74, 0x4c, 0xdd, 0xab, 0x2c, 0x5f, 0x7f, 0x8d, - 0x42, 0x1c, 0xd4, 0xb3, 0xd1, 0x36, 0xb7, 0xde, 0x17, 0x82, 0xf3, 0xae, 0xd7, 0x17, 0x3c, 0xa7, - 0xd7, 0x17, 0x3c, 0x61, 0xd7, 0x16, 0x9e, 0x0c, 0x51, 0xf5, 0x72, 0x6c, 0xeb, 0x20, 0xa3, 0x65, - 0xd3, 0x50, 0x9f, 0x8e, 0x5a, 0x34, 0x9c, 0xec, 0xc3, 0xc4, 0x4f, 0x3a, 0x32, 0x29, 0x53, 0x03, - 0xd0, 0x1a, 0xec, 0x5a, 0xdd, 0x6f, 0xe6, 0xae, 0x18, 0xca, 0xab, 0x56, 0x7e, 0xaa, 0xa2, 0xd8, - 0x48, 0xd2, 0x69, 0x49, 0x7f, 0xd5, 0xd2, 0xe2, 0x35, 0x93, 0x2c, 0x00, 0x9a, 0x88, 0xea, 0x1d, - 0x03, 0x02, 0x4d, 0x7e, 0x9f, 0x37, 0xed, 0xf7, 0x41, 0x29, 0x1a, 0x38, 0xd1, 0x8a, 0x80, 0x33, - 0x92, 0xc0, 0x5d, 0x2c, 0x36, 0x06, 0x3f, 0x74, 0x26, 0xc2, 0x98, 0xfc, 0xd4, 0x8a, 0x8e, 0x4e, - 0x49, 0x2f, 0xbe, 0x60, 0xc4, 0xb1, 0xeb, 0xe2, 0xbe, 0x58, 0x7f, 0x01, 0x81, 0x6f, 0x5b, 0xb3, - 0x48, 0xe8, 0xb4, 0x38, 0x3f, 0x2d, 0x20, 0xd7, 0x34, 0xf2, 0x10, 0x69, 0x44, 0x7e, 0x42, 0x44, - 0xe4, 0x2e, 0xda, 0xe4, 0xdd, 0x89, 0x9a, 0xe8, 0xf6, 0x40, 0x6d, 0xf4, 0xcf, 0x30, 0x0b, 0xa1, - 0xe3, 0x23, 0xbb, 0xbb, 0xf4, 0x13, 0x94, 0xc6, 0x1c, 0xe4, 0xde, 0xe4, 0xdf, 0x80, 0x9b, 0x72, - 0x34, 0x1d, 0x61, 0x9c, 0x9d, 0x60, 0xec, 0xc2, 0x31, 0xd0, 0x3b, 0x77, 0xd5, 0xd8, 0x96, 0x03, - 0xd6, 0x51, 0xeb, 0xd3, 0x36, 0x8d, 0x57, 0x8b, 0x89, 0x20, 0xbd, 0xa5, 0x11, 0xee, 0xc8, 0x8f, - 0xfe, 0x98, 0xfc, 0x59, 0xc7, 0x8f, 0x60, 0xa4, 0xa3, 0x1d, 0xd6, 0xcd, 0x26, 0xd3, 0xe4, 0x9b, - 0x05, 0x54, 0xf1, 0x02, 0x57, 0xb5, 0x99, 0xce, 0xfb, 0x0c, 0xc1, 0xb0, 0x65, 0x94, 0xb8, 0x19, - 0x26, 0x7a, 0x0c, 0xb4, 0x38, 0x90, 0xbe, 0x6e, 0x47, 0x34, 0x48, 0x84, 0x31, 0xd4, 0xaa, 0xfd, - 0x48, 0x91, 0x4b, 0x8b, 0x54, 0xde, 0x93, 0x60, 0x16, 0x52, 0x09, 0x94, 0x89, 0xf0, 0xce, 0x42, - 0xcc, 0x77, 0xab, 0xfd, 0x94, 0xb5, 0xfa, 0x5e, 0x25, 0x92, 0x6a, 0x1e, 0x3f, 0xce, 0x16, 0xb5, - 0x34, 0x70, 0xc6, 0x62, 0x6a, 0x84, 0xde, 0x64, 0x7d, 0xca, 0x00, 0x44, 0xcf, 0x74, 0xba, 0xc6, - 0x6c, 0xa5, 0x2a, 0x33, 0x83, 0x4b, 0xeb, 0xe1, 0x88, 0x14, 0x63, 0xd8, 0xc5, 0x1f, 0x57, 0xf1, - 0x5a, 0x3f, 0x5a, 0xf5, 0x44, 0x54, 0xf8, 0x80, 0x51, 0xb1, 0xf9, 0x7d, 0xad, 0xde, 0x72, 0xb6, - 0x1a, 0x2f, 0x37, 0x67, 0x6f, 0xa5, 0x31, 0x78, 0xeb, 0x4a, 0xe5, 0x09, 0xe9, 0xc6, 0x99, 0x11, - 0xd6, 0x06, 0x43, 0x39, 0x3a, 0x4f, 0x6f, 0xc4, 0xb0, 0x2b, 0x47, 0x81, 0xd3, 0x41, 0x73, 0x6b, - 0x95, 0xff, 0xc6, 0x24, 0x5e, 0x37, 0x01, 0x8b, 0xc9, 0x34, 0x7e, 0x6e, 0x8e, 0xad, 0x6f, 0x99, - 0xcd, 0xed, 0xe7, 0x0f, 0x52, 0xd1, 0xde, 0x9d, 0xba, 0x16, 0x20, 0x1e, 0x95, 0xfc, 0x15, 0x8b, - 0x31, 0x28, 0x20, 0x13, 0x98, 0xe0, 0x91, 0x44, 0x82, 0xf2, 0xbf, 0xc8, 0x41, 0xbc, 0x7e, 0xff, - 0x10, 0x1b, 0xf7, 0x03, 0x7b, 0x73, 0x4e, 0x23, 0x9d, 0xc0, 0x5d, 0x40, 0xd0, 0xf5, 0xe5, 0x5d, - 0x1d, 0x78, 0x48, 0x17, 0xa2, 0xf3, 0x49, 0xe2, 0x05, 0xf5, 0x37, 0x9c, 0x29, 0x97, 0xee, 0x3e, - 0x44, 0x57, 0xf2, 0xab, 0x90, 0xd5, 0xb9, 0x84, 0xcd, 0x72, 0x6b, 0xd8, 0x6d, 0xee, 0xd1, 0x43, - 0xff, 0xe5, 0xd1, 0x2f, 0x72, 0x4e, 0xd7, 0xef, 0xa0, 0x32, 0x45, 0xc8, 0x9a, 0x19, 0x13, 0x62, - 0x12, 0x0d, 0x60, 0xe8, 0x0d, 0x90, 0x10, 0x91, 0xe6, 0xd0, 0x5e, 0x5c, 0xb6, 0xa0, 0xdb, 0x84, - 0x00, 0x67, 0x60, 0x25, 0xe4, 0x18, 0x69, 0x9e, 0x6f, 0x05, 0x12, 0xcf, 0xf4, 0xd7, 0xef, 0xb6, - 0x55, 0xfe, 0xf3, 0x09, 0x9a, 0xb2, 0xe7, 0x21, 0x67, 0xa5, 0xb6, 0x8e, 0x61, 0x5f, 0x1d, 0x01, - 0x9a, 0x33, 0x85, 0x4f, 0x71, 0x93, 0x83, 0x5c, 0xde, 0xb4, 0x0d, 0xd9, 0x69, 0xdc, 0x4d, 0x6e, - 0xd9, 0x68, 0x6b, 0x7d, 0x71, 0x26, 0x8a, 0xf2, 0x98, 0x74, 0xbf, 0x72, 0x0e, 0x47, 0xaf, 0xdb, - 0x4e, 0xfd, 0x40, 0x3e, 0xb3, 0x42, 0x66, 0xd7, 0x9c, 0x7d, 0xa4, 0x60, 0x8e, 0x86, 0xdd, 0xfa, - 0x05, 0x02, 0x86, 0x87, 0xd5, 0x9e, 0xad, 0x1f, 0x6c, 0x3a, 0xa6, 0x4d, 0xc7, 0x69, 0x76, 0xfd, - 0xb8, 0x6f, 0xe3, 0x2b, 0x75, 0xbc, 0xac, 0xa1, 0xcb, 0xca, 0xc4, 0x20, 0x40, 0x5b, 0xa6, 0xca, - 0x9f, 0xba, 0xb0, 0xb6, 0xca, 0x56, 0xe3, 0x81, 0x1f, 0xcd, 0xfb, 0x53, 0x23, 0x84, 0x1a, 0x34, - 0xf9, 0xec, 0x2b, 0x8d, 0x64, 0x8e, 0x76, 0x5f, 0x1c, 0xf4, 0x7a, 0xbd, 0xbf, 0x0c, 0x82, 0xb7, - 0x9b, 0x97, 0x43, 0xb8, 0xce, 0xb7, 0x29, 0x23, 0x70, 0x38, 0x0a, 0xd6, 0xfd, 0x12, 0x37, 0x36, - 0xfd, 0xe2, 0x2e, 0xf0, 0xc4, 0xeb, 0xd6, 0xee, 0x8b, 0xd7, 0xaf, 0x5e, 0xbd, 0x22, 0xaf, 0x55, - 0x91, 0x7b, 0xba, 0x53, 0x72, 0x36, 0xab, 0x20, 0x69, 0xbc, 0xfb, 0x12, 0xab, 0x81, 0x99, 0xbd, - 0x5c, 0xff, 0x1f, 0x4b, 0x55, 0x22, 0xc1, 0x2f, 0x7d, 0x2a, 0xea, 0x54, 0x82, 0xf7, 0xa3, 0xf6, - 0x3e, 0xdb, 0x92, 0x39, 0x49, 0x92, 0x76, 0xb3, 0xf9, 0xb3, 0x6c, 0xac, 0x80, 0xdd, 0xfa, 0x9f, - 0x90, 0xed, 0x12, 0x85, 0xf0, 0x8b, 0x68, 0x46, 0x9c, 0xa3, 0x7f, 0x64, 0xfd, 0x07, 0xe9, 0x71, - 0x3b, 0x45, 0xde, 0x12, 0x00, 0x00 + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0xa5, 0x58, 0x6b, 0x73, 0xdb, 0xb8, + 0x15, 0xfd, 0xee, 0x5f, 0x41, 0x23, 0x1e, 0x9b, 0x1c, 0xd1, 0x94, 0x1c, 0x77, 0xb7, 0x89, 0x24, + 0xc8, 0x1b, 0xe7, 0xd1, 0xb8, 0x93, 0xc4, 0x9e, 0x71, 0x76, 0x3b, 0x1d, 0xd7, 0xb3, 0xa6, 0x48, + 0x48, 0x42, 0x4c, 0x01, 0x1c, 0x00, 0xf4, 0xa3, 0xb2, 0xfe, 0x7b, 0xcf, 0x05, 0x49, 0x59, 0x72, + 0x9c, 0xdd, 0x76, 0xfa, 0x45, 0x12, 0x80, 0x8b, 0x8b, 0x8b, 0x73, 0xcf, 0x7d, 0x40, 0xc3, 0xed, + 0x77, 0xa7, 0x6f, 0xbf, 0xfe, 0xf3, 0xec, 0x7d, 0x30, 0x73, 0xf3, 0x62, 0x34, 0x6c, 0x3e, 0x45, + 0x9a, 0x07, 0x45, 0xaa, 0xa6, 0x9c, 0x09, 0xc5, 0x46, 0xc3, 0xb9, 0x70, 0x69, 0x90, 0xcd, 0x52, + 0x63, 0x85, 0xe3, 0xac, 0x72, 0x93, 0xfd, 0x57, 0xed, 0xec, 0x96, 0x4a, 0xe7, 0x82, 0xb3, 0x1b, + 0x29, 0x6e, 0x4b, 0x6d, 0x1c, 0x0b, 0x32, 0xad, 0x9c, 0x50, 0x10, 0xbb, 0x95, 0xb9, 0x9b, 0xf1, + 0x9f, 0x7a, 0xbd, 0x95, 0xe8, 0x93, 0xa5, 0x5c, 0xdc, 0xc8, 0x4c, 0xec, 0xfb, 0x41, 0x2c, 0x95, + 0x74, 0x32, 0x2d, 0xf6, 0x6d, 0x96, 0x16, 0x82, 0x1f, 0xc4, 0xf3, 0xf4, 0x4e, 0xce, 0xab, 0xf9, + 0x6a, 0x5c, 0x59, 0x61, 0xfc, 0x20, 0x1d, 0x63, 0xac, 0x34, 0xfb, 0xee, 0xe4, 0xd1, 0xd0, 0x49, + 0x57, 0x88, 0xd1, 0xaf, 0x90, 0x9c, 0xeb, 0x3c, 0x38, 0x17, 0xce, 0x49, 0x35, 0xb5, 0xc3, 0x6e, + 0x3d, 0x3f, 0xb4, 0x99, 0x91, 0xa5, 0x1b, 0x6d, 0xdd, 0xa4, 0x26, 0xd0, 0xb7, 0x4a, 0x98, 0xb8, + 0xd0, 0x99, 0x2c, 0xe3, 0xca, 0xe8, 0x5b, 0x1b, 0xe7, 0x3c, 0xd7, 0x59, 0x35, 0x87, 0x7d, 0x71, + 0x35, 0x7f, 0x3b, 0x99, 0xf2, 0xc5, 0x32, 0x2e, 0xa5, 0xb2, 0xfc, 0xe2, 0xe7, 0xf8, 0xaf, 0xf1, + 0xab, 0xf8, 0x75, 0x7c, 0xd0, 0x8b, 0x0f, 0x0e, 0x2e, 0x69, 0xf2, 0x94, 0x5f, 0x30, 0x63, 0x6f, + 0x72, 0x16, 0xff, 0xf9, 0xd7, 0x25, 0x9d, 0xc2, 0xb7, 0x0f, 0x62, 0x55, 0xcd, 0x3f, 0xf3, 0xde, + 0x60, 0x52, 0xa9, 0xcc, 0x49, 0xad, 0x82, 0xe9, 0x49, 0x1e, 0x8a, 0x68, 0x61, 0x84, 0xab, 0x8c, + 0x0a, 0xf2, 0x64, 0x2a, 0xdc, 0xfb, 0x42, 0x90, 0x01, 0xc7, 0xf7, 0x7e, 0x69, 0xb9, 0x12, 0x95, + 0xf6, 0x74, 0x4d, 0x54, 0xec, 0xee, 0x32, 0x3d, 0xfe, 0x26, 0x32, 0xc7, 0x38, 0x77, 0xf7, 0xa5, + 0xd0, 0x13, 0x9a, 0xdb, 0x7e, 0x63, 0x4c, 0x7a, 0x9f, 0x48, 0xeb, 0xbf, 0x37, 0xf6, 0x7f, 0x0c, + 0xa3, 0xc5, 0xad, 0x54, 0xb9, 0xbe, 0x4d, 0x74, 0x29, 0x54, 0xc8, 0x66, 0xce, 0x95, 0xb6, 0xdf, + 0xed, 0x4e, 0xa5, 0x9b, 0x55, 0xe3, 0x24, 0xd3, 0xf3, 0xee, 0x1b, 0x69, 0x32, 0xad, 0xf5, 0xb5, + 0x14, 0xdd, 0x7f, 0x7c, 0x7a, 0xff, 0xae, 0x7b, 0x2b, 0xaf, 0x65, 0xb7, 0xc5, 0xf0, 0x45, 0x55, + 0x83, 0xba, 0x6f, 0x9b, 0x09, 0xb6, 0xa6, 0xfd, 0xf8, 0xa9, 0xf6, 0xee, 0x4a, 0x2a, 0x66, 0xbf, + 0x5b, 0x51, 0x4c, 0xd6, 0xa5, 0x0b, 0x9d, 0xe6, 0x7f, 0x3f, 0x0f, 0x45, 0xec, 0xf8, 0x76, 0x2f, + 0x5a, 0x14, 0xc2, 0x05, 0x8a, 0xe7, 0x49, 0x66, 0x44, 0xea, 0x44, 0x03, 0x40, 0xc8, 0x6a, 0x5f, + 0xb1, 0x68, 0xa0, 0x12, 0x28, 0x7b, 0xe3, 0x9c, 0x91, 0xe3, 0xca, 0x09, 0x2c, 0x98, 0x8c, 0xc5, + 0x22, 0x8a, 0x9f, 0xce, 0x13, 0x0e, 0x38, 0xce, 0x89, 0x3b, 0xd7, 0xfd, 0x96, 0xde, 0xa4, 0xad, + 0x82, 0xef, 0x04, 0x53, 0x7b, 0xaf, 0xa0, 0xc2, 0x45, 0x71, 0x9e, 0x8c, 0x75, 0x7e, 0x9f, 0xa4, + 0x25, 0x8c, 0xce, 0xdf, 0xce, 0x64, 0x91, 0x87, 0x8a, 0xe4, 0xd3, 0x3c, 0x7f, 0x7f, 0x03, 0x2b, + 0x3e, 0x49, 0x0b, 0xba, 0x0a, 0x13, 0x32, 0xb2, 0x99, 0xc5, 0x61, 0xc4, 0x47, 0x8b, 0xbf, 0x09, + 0xf7, 0x5b, 0x18, 0x2d, 0x9f, 0x97, 0x13, 0xc6, 0x68, 0x03, 0xf3, 0x20, 0x07, 0xae, 0x5b, 0x5d, + 0x88, 0xa4, 0xd0, 0xd3, 0x90, 0xbd, 0xa7, 0xf9, 0xa0, 0xb9, 0x3c, 0x80, 0x09, 0x26, 0xb2, 0x10, + 0xfe, 0x1a, 0x20, 0xb7, 0xc1, 0x75, 0x3f, 0x35, 0xf3, 0xf0, 0x24, 0x36, 0x4e, 0xe4, 0xb4, 0x32, + 0xa9, 0x47, 0xab, 0xbe, 0x46, 0x30, 0x49, 0xb1, 0x21, 0x4f, 0xfe, 0xa5, 0x4e, 0x14, 0x7c, 0x55, + 0x02, 0x34, 0x11, 0x94, 0xe9, 0x54, 0x04, 0x79, 0xea, 0xd2, 0x6d, 0xc0, 0xbb, 0x06, 0xf0, 0x39, + 0xdc, 0xc1, 0xe8, 0x80, 0x3e, 0xe8, 0xd1, 0xf8, 0x05, 0x14, 0xf4, 0xfa, 0x92, 0xd2, 0x68, 0xa7, + 0x33, 0x5d, 0xec, 0xee, 0x86, 0x9e, 0x96, 0xbd, 0x38, 0xf4, 0x41, 0xc0, 0x49, 0xa2, 0x38, 0x77, + 0xda, 0x40, 0x2b, 0x51, 0xf1, 0xc4, 0x89, 0x39, 0x5d, 0x3c, 0x3b, 0x29, 0x59, 0x14, 0x3d, 0x3c, + 0x34, 0x62, 0xd8, 0x3f, 0x2f, 0x61, 0xf0, 0x07, 0xe8, 0x0f, 0x3e, 0xeb, 0x5c, 0x24, 0xc1, 0x59, + 0x21, 0x52, 0x2b, 0x02, 0x00, 0x21, 0x4c, 0x40, 0xd4, 0x09, 0x4e, 0xce, 0x60, 0x52, 0xbc, 0xa1, + 0xd1, 0x6e, 0x6a, 0xac, 0x23, 0x2f, 0x8a, 0x20, 0x95, 0xc3, 0x5e, 0x1f, 0x1b, 0x38, 0x83, 0x42, + 0x82, 0x55, 0x73, 0x16, 0x25, 0x52, 0x01, 0xd0, 0x8f, 0x5f, 0x3f, 0x7f, 0xe2, 0xec, 0x8b, 0x0e, + 0x9a, 0x90, 0xb6, 0x01, 0xe2, 0xd1, 0xa5, 0x05, 0x41, 0xc1, 0x36, 0xc2, 0xe3, 0xc3, 0x7a, 0x78, + 0x70, 0xce, 0x3b, 0x88, 0x07, 0xb1, 0xcd, 0x79, 0xd8, 0x7b, 0xd8, 0x8c, 0xa3, 0x93, 0xe7, 0x04, + 0xf9, 0x77, 0x82, 0xd9, 0x4c, 0x64, 0xd7, 0xc4, 0xd1, 0x68, 0x41, 0xd9, 0x42, 0x71, 0x91, 0x50, + 0xb6, 0x49, 0x8c, 0x28, 0x8b, 0x34, 0x03, 0x8b, 0x2e, 0x2e, 0x41, 0x36, 0xd8, 0x69, 0xab, 0xb1, + 0x75, 0x26, 0xdc, 0x3f, 0x8c, 0x06, 0x72, 0x12, 0x32, 0xdc, 0x63, 0x2c, 0x0c, 0x70, 0x17, 0x09, + 0x11, 0x12, 0x81, 0x8a, 0x6c, 0x81, 0xa1, 0x6a, 0x05, 0x7b, 0xf1, 0x61, 0x14, 0x4d, 0xb4, 0x09, + 0x49, 0xad, 0x44, 0x3a, 0x90, 0x43, 0x4a, 0x32, 0x49, 0x21, 0xd4, 0xd4, 0xcd, 0x06, 0xb2, 0xd3, + 0x89, 0xa0, 0xc7, 0x6d, 0x73, 0xca, 0x32, 0x17, 0xf2, 0x32, 0x5a, 0x60, 0x28, 0x92, 0x9b, 0xb4, + 0xa8, 0x60, 0x26, 0x89, 0x62, 0xf2, 0xe1, 0xa1, 0x99, 0x19, 0xee, 0x1f, 0xac, 0x7e, 0x8f, 0x0e, + 0x5f, 0x47, 0x0b, 0x00, 0xed, 0xee, 0xc1, 0x3a, 0x78, 0x58, 0x1b, 0xce, 0x8c, 0xc8, 0xd9, 0x60, + 0x8c, 0xc8, 0xba, 0x5e, 0x6e, 0xae, 0xac, 0xf6, 0x1c, 0x1e, 0x31, 0x38, 0x48, 0x4d, 0x05, 0xeb, + 0xb3, 0x17, 0x93, 0xc9, 0x84, 0x2d, 0x1f, 0x41, 0x00, 0x0b, 0xce, 0x70, 0x20, 0x21, 0x06, 0x23, + 0xea, 0x1c, 0xe4, 0x6d, 0x27, 0x6e, 0xbb, 0x0b, 0x15, 0xcb, 0x4b, 0xf0, 0xf5, 0xd4, 0x67, 0xa2, + 0x04, 0xee, 0x37, 0x52, 0x90, 0x70, 0xd4, 0x08, 0xcb, 0x28, 0xf2, 0x59, 0x96, 0xab, 0xb8, 0xd5, + 0x24, 0xa3, 0x81, 0x28, 0xc0, 0x15, 0x82, 0xaa, 0x05, 0xe6, 0x0f, 0x20, 0x25, 0x4d, 0x9b, 0x49, + 0x4d, 0x3e, 0x82, 0xe7, 0x00, 0x9e, 0x1b, 0xca, 0x16, 0x39, 0x47, 0xc8, 0x5d, 0xb8, 0xcb, 0x11, + 0xef, 0x81, 0xdb, 0x1e, 0xd3, 0xb2, 0xb2, 0xb3, 0x90, 0xe6, 0x22, 0x9f, 0xb3, 0xeb, 0xb1, 0x37, + 0x29, 0x6a, 0xed, 0xf8, 0x4e, 0xfa, 0xc7, 0xa2, 0x3f, 0x30, 0xe5, 0x19, 0x33, 0x56, 0xb7, 0xa5, + 0xa3, 0x1f, 0xe1, 0x44, 0xba, 0xf8, 0x20, 0x05, 0x92, 0x0c, 0x68, 0x15, 0x03, 0x3c, 0xd4, 0x84, + 0x15, 0xb0, 0x2a, 0x8a, 0x16, 0xbe, 0x0c, 0x75, 0xf8, 0xde, 0x70, 0x66, 0x02, 0xef, 0xab, 0xa6, + 0x4e, 0xf6, 0x5f, 0xfe, 0xdc, 0x2b, 0xef, 0xd8, 0x68, 0x6f, 0xf0, 0x88, 0xbd, 0x8c, 0xcd, 0x33, + 0xd8, 0x43, 0x0b, 0xab, 0xd4, 0xb5, 0x82, 0xe1, 0x80, 0x96, 0x3b, 0xe2, 0x86, 0x54, 0x59, 0x51, + 0xe5, 0x58, 0x84, 0x83, 0xa3, 0xa3, 0x35, 0x1b, 0xa0, 0x22, 0xea, 0x3f, 0x8e, 0x3b, 0x58, 0xef, + 0x38, 0x3f, 0xbb, 0x7c, 0xfe, 0xc2, 0xea, 0x11, 0x7b, 0x83, 0x4b, 0x9b, 0xa1, 0x6a, 0x2f, 0x6d, + 0x70, 0xe9, 0xcd, 0xdb, 0x5d, 0x98, 0xcb, 0x18, 0xd9, 0xdd, 0x43, 0xe7, 0x23, 0xc8, 0xc6, 0xba, + 0x2d, 0x55, 0x6a, 0x60, 0x6f, 0xa5, 0xcb, 0x80, 0x6f, 0xb4, 0xc8, 0x90, 0x39, 0xd8, 0x58, 0x23, + 0x51, 0xa6, 0x8a, 0xf5, 0x35, 0x67, 0x3e, 0xf0, 0xc6, 0xfa, 0x8e, 0xc5, 0x96, 0xef, 0xd5, 0xac, + 0x67, 0xce, 0x54, 0x82, 0xed, 0x75, 0x42, 0x75, 0xc4, 0xea, 0xc0, 0x04, 0xab, 0xfb, 0x60, 0x4a, + 0xcd, 0xec, 0x81, 0xd7, 0xd1, 0x04, 0x5e, 0xdf, 0xf2, 0xab, 0x66, 0xd7, 0xce, 0x42, 0x2d, 0xd9, + 0x55, 0xdc, 0xf0, 0x8c, 0xbb, 0x35, 0x5e, 0x1d, 0x85, 0x84, 0x73, 0x80, 0x16, 0x83, 0xb3, 0xc3, + 0xd7, 0x2c, 0x98, 0x4b, 0xc5, 0xd9, 0xfe, 0x01, 0xb4, 0x17, 0xa9, 0xb5, 0x9c, 0x59, 0xb6, 0x07, + 0x73, 0x99, 0x54, 0xa8, 0x1f, 0x7d, 0x2f, 0x8a, 0x04, 0x5f, 0x72, 0x96, 0xaa, 0xfb, 0x95, 0xcc, + 0xdd, 0x5d, 0xc1, 0xf6, 0x1a, 0x0b, 0x72, 0x31, 0x49, 0xab, 0xc2, 0x91, 0xfd, 0x54, 0x7f, 0xc8, + 0xf6, 0x0d, 0x2b, 0x9e, 0xb8, 0xf3, 0x27, 0xb8, 0x73, 0xc0, 0xae, 0x96, 0x4f, 0x9c, 0x03, 0x22, + 0x36, 0x14, 0x10, 0xad, 0xad, 0x24, 0x91, 0x8b, 0xbb, 0xd3, 0x89, 0x17, 0xe8, 0x1c, 0x20, 0x5f, + 0x36, 0x22, 0x57, 0xc1, 0xce, 0xc2, 0x2d, 0xfb, 0x01, 0x2e, 0xb8, 0x82, 0x8c, 0x73, 0x7d, 0xd4, + 0x2e, 0x0f, 0xa5, 0x2a, 0x2b, 0x17, 0x10, 0xe4, 0x9c, 0xcd, 0x64, 0x9e, 0xa3, 0x8f, 0x0b, 0xea, + 0x86, 0x69, 0x67, 0x21, 0x96, 0x7d, 0xda, 0xbd, 0xb3, 0x90, 0x47, 0x14, 0x75, 0xc0, 0x12, 0x36, + 0x36, 0x06, 0x4f, 0x52, 0xb8, 0x8c, 0x8d, 0xae, 0xfa, 0x12, 0xf9, 0xf8, 0xff, 0xd6, 0xb6, 0xb3, + 0xd0, 0x4b, 0x28, 0x7b, 0x34, 0x7b, 0x43, 0xd3, 0xce, 0xc2, 0x63, 0xcc, 0xc9, 0xf0, 0x95, 0x07, + 0xb1, 0xe1, 0x8f, 0x55, 0xef, 0x2c, 0xec, 0x12, 0xb5, 0xd4, 0x2b, 0x6a, 0x08, 0x13, 0xba, 0x99, + 0xb4, 0xf1, 0xde, 0xce, 0xe2, 0xc7, 0xc8, 0x2d, 0xf7, 0x22, 0x74, 0x88, 0x63, 0x33, 0xba, 0x5a, + 0x6e, 0x84, 0xe4, 0x3b, 0xa3, 0x4b, 0x54, 0x48, 0x55, 0x27, 0xfb, 0x1f, 0x75, 0x23, 0xa2, 0xa0, + 0x6e, 0x2b, 0x42, 0xd0, 0xae, 0xf7, 0x69, 0xf6, 0xf8, 0xfe, 0x0b, 0x2c, 0x6d, 0x83, 0x27, 0xba, + 0x38, 0xb8, 0xa4, 0x2a, 0xb0, 0x51, 0xfa, 0xd7, 0x8e, 0xc0, 0xfe, 0xf5, 0x25, 0xe4, 0x1a, 0x89, + 0x02, 0x71, 0xf2, 0xe5, 0xec, 0xd7, 0xaf, 0x84, 0x81, 0x4c, 0x5c, 0x3a, 0x25, 0x7d, 0x20, 0x42, + 0xcd, 0xa3, 0x7a, 0x12, 0x50, 0x3d, 0x3c, 0x3c, 0x56, 0x96, 0x66, 0x2a, 0xaa, 0x8d, 0x15, 0x18, + 0x7a, 0xac, 0x07, 0xd2, 0x57, 0xa8, 0xc1, 0x66, 0x88, 0xca, 0x24, 0x6d, 0x3b, 0x9f, 0x55, 0x8d, + 0xe9, 0x74, 0x4c, 0x5d, 0xd5, 0x2c, 0x5f, 0x5f, 0x46, 0xc8, 0x0e, 0xea, 0x2e, 0x6a, 0x9b, 0x5b, + 0xaf, 0x0b, 0xc6, 0x79, 0xd5, 0xeb, 0x13, 0x9e, 0xfd, 0xeb, 0x13, 0x9e, 0xda, 0x6b, 0x13, 0x4f, + 0xda, 0xad, 0x7a, 0x3a, 0xb6, 0xb5, 0x91, 0xd1, 0xb2, 0x29, 0xbd, 0x4f, 0x9b, 0x32, 0x6a, 0x63, + 0xf6, 0x21, 0xe2, 0x7b, 0x22, 0x99, 0x94, 0xa9, 0x01, 0xbc, 0x0d, 0xca, 0x6d, 0x85, 0x68, 0x3a, + 0xb4, 0x18, 0xb8, 0xa9, 0x95, 0x9e, 0xaa, 0x28, 0x36, 0xdc, 0x79, 0x5a, 0xd2, 0xaf, 0x3a, 0x09, + 0xf9, 0xec, 0x4a, 0x12, 0x00, 0x4d, 0x44, 0xf5, 0x8e, 0x01, 0x81, 0x26, 0xbf, 0xf7, 0xb0, 0xf6, + 0xfb, 0x90, 0x53, 0x1a, 0x38, 0x51, 0xb4, 0x80, 0x33, 0x9c, 0xc0, 0x5d, 0x2c, 0x36, 0x5a, 0x44, + 0xd4, 0x30, 0xc2, 0x98, 0xf4, 0xd4, 0xb9, 0x1f, 0x35, 0x95, 0x16, 0xbe, 0xa0, 0x19, 0xb2, 0xeb, + 0x65, 0x60, 0xb1, 0xbe, 0x80, 0x52, 0xd0, 0x16, 0x71, 0x91, 0xd0, 0x6d, 0x71, 0x7f, 0x9a, 0x80, + 0xaf, 0xa9, 0x39, 0x22, 0x7a, 0x89, 0xfc, 0x84, 0x28, 0xcb, 0x5d, 0xb4, 0xc9, 0xd0, 0x13, 0x35, + 0xd1, 0xed, 0x85, 0x5a, 0xeb, 0x9f, 0xe1, 0x20, 0x4c, 0xc7, 0x21, 0xbb, 0xbb, 0xf4, 0x09, 0xf2, + 0xa3, 0x63, 0x72, 0x6f, 0xf2, 0x6f, 0xc0, 0x4d, 0x39, 0xea, 0xa3, 0xc0, 0xc4, 0x09, 0x1a, 0x34, + 0x5c, 0x03, 0x55, 0x76, 0x57, 0x8d, 0x6d, 0x39, 0x60, 0x1d, 0xb5, 0xde, 0x97, 0x53, 0x23, 0xb6, + 0x98, 0x08, 0xca, 0xcc, 0xd4, 0xec, 0x1d, 0xf9, 0x47, 0x02, 0xde, 0x08, 0xac, 0xe3, 0x9b, 0x35, + 0xca, 0xb8, 0x1d, 0xd6, 0xcd, 0x26, 0xd3, 0xe4, 0x9b, 0x05, 0x54, 0xf1, 0x02, 0x8f, 0xba, 0x99, + 0xce, 0xfb, 0x0c, 0xc6, 0xb0, 0x65, 0x94, 0xb8, 0x19, 0x7a, 0x7f, 0xb4, 0xbe, 0xb8, 0x90, 0xbe, + 0x6e, 0x9b, 0x39, 0x24, 0x13, 0x63, 0xa8, 0xa8, 0xfb, 0xe6, 0x23, 0x97, 0x16, 0xae, 0xbc, 0xa7, + 0xd4, 0x5a, 0x48, 0x25, 0x10, 0x10, 0xc2, 0x2b, 0x0b, 0xd1, 0x09, 0xae, 0xf6, 0x93, 0xd7, 0xea, + 0x17, 0x98, 0x48, 0xaa, 0x79, 0xfc, 0xd8, 0x85, 0xd4, 0x49, 0x84, 0x33, 0x16, 0x53, 0xc9, 0xf4, + 0x22, 0xeb, 0xfd, 0x08, 0x20, 0x7a, 0xa6, 0x26, 0x36, 0x62, 0xab, 0xfc, 0x33, 0x33, 0x78, 0xde, + 0x1e, 0x8e, 0x28, 0xb7, 0x0c, 0xbb, 0xf8, 0x71, 0x15, 0xaf, 0x55, 0xae, 0x55, 0xf5, 0x44, 0x2e, + 0x18, 0x30, 0x0a, 0x36, 0xbf, 0xaf, 0xcd, 0xcc, 0x9c, 0xad, 0x1a, 0xd1, 0xcd, 0x2e, 0x5d, 0x69, + 0xb4, 0xe8, 0xba, 0x52, 0x79, 0x42, 0x19, 0xe6, 0xcc, 0x08, 0x6b, 0x83, 0xa1, 0x1c, 0x9d, 0xa7, + 0x37, 0x62, 0xd8, 0x95, 0xa3, 0xc0, 0xe9, 0xa0, 0x79, 0xdf, 0xca, 0x7f, 0xa3, 0x67, 0xaf, 0xcb, + 0x85, 0x45, 0x0f, 0x1b, 0x3f, 0xd7, 0xf1, 0xd6, 0xef, 0xd1, 0xe6, 0x9d, 0xf4, 0x07, 0xae, 0x68, + 0x5f, 0x59, 0x5d, 0x0b, 0x10, 0x8f, 0x4a, 0xfe, 0x8a, 0xc5, 0x68, 0x29, 0xe0, 0x09, 0xf4, 0xfa, + 0x70, 0x22, 0x41, 0xf9, 0x5f, 0xf8, 0x60, 0x23, 0x27, 0x89, 0x8d, 0x97, 0x84, 0xbd, 0x39, 0xa7, + 0xe6, 0x4f, 0xe0, 0xd5, 0x20, 0xe8, 0xa1, 0xf3, 0xae, 0x36, 0x3c, 0xa4, 0xa7, 0xd3, 0xf9, 0x24, + 0xf1, 0xa9, 0xf7, 0x37, 0xdc, 0x29, 0x97, 0xee, 0x3e, 0x44, 0xfd, 0xf2, 0xb3, 0x48, 0xc0, 0x73, + 0x09, 0x99, 0xe5, 0xd6, 0xb0, 0xdb, 0xbc, 0xb8, 0x87, 0xfe, 0xe4, 0xd1, 0x2f, 0x72, 0x4e, 0x0f, + 0xf5, 0xa0, 0x32, 0x45, 0xc8, 0x9a, 0x6e, 0x14, 0xc9, 0x24, 0x1a, 0x40, 0xd0, 0x0b, 0xc0, 0x21, + 0x22, 0xcd, 0x91, 0xa5, 0xf1, 0x2c, 0x43, 0x86, 0x27, 0x04, 0x38, 0x03, 0x2b, 0x91, 0xb8, 0xe1, + 0xe6, 0xf9, 0x56, 0x20, 0x31, 0xa6, 0x5f, 0xbf, 0xdb, 0xb6, 0x46, 0x9c, 0x4f, 0x50, 0xbe, 0x3d, + 0x0f, 0x39, 0x2b, 0xb5, 0x75, 0x0c, 0xfb, 0x6a, 0x0b, 0x50, 0xc6, 0xc9, 0x7c, 0xb2, 0x9b, 0x14, + 0xe4, 0xf2, 0xa6, 0x2d, 0xdd, 0x4e, 0xe3, 0x15, 0x73, 0xcb, 0x46, 0x5b, 0xeb, 0x93, 0x33, 0x51, + 0x94, 0xc7, 0x54, 0x21, 0x2a, 0xe7, 0x70, 0xf5, 0xba, 0x40, 0xd5, 0x03, 0xd2, 0x99, 0x15, 0x32, + 0xbb, 0xe6, 0xec, 0x23, 0x19, 0x73, 0x34, 0xec, 0xd6, 0x0b, 0x30, 0x18, 0x1a, 0x56, 0x7b, 0xb6, + 0x7e, 0xb0, 0xe9, 0x98, 0x36, 0x1d, 0xa7, 0xd9, 0xf5, 0xe3, 0xbe, 0x8d, 0x53, 0x6a, 0x7b, 0x59, + 0x43, 0x97, 0x95, 0x88, 0x81, 0x81, 0xb6, 0x4c, 0x95, 0xbf, 0x75, 0x61, 0x6d, 0x95, 0xad, 0x1a, + 0x09, 0xdf, 0xc4, 0xf7, 0xa7, 0x46, 0x08, 0x35, 0x68, 0xfc, 0xd9, 0x57, 0x1a, 0xce, 0x1c, 0xed, + 0xbe, 0x38, 0xe8, 0xf5, 0x7a, 0x7f, 0x19, 0x04, 0x6f, 0x37, 0x9f, 0x91, 0x50, 0x9d, 0x6f, 0x93, + 0x47, 0xa0, 0x70, 0x14, 0xac, 0xeb, 0x25, 0x6e, 0x6c, 0xea, 0xc5, 0xab, 0xe1, 0x89, 0xd6, 0xad, + 0xdd, 0x17, 0xaf, 0x5f, 0xbd, 0x7a, 0x45, 0x5a, 0xab, 0x22, 0xf7, 0x74, 0x27, 0xe7, 0x6c, 0x46, + 0x41, 0xd2, 0x68, 0xf7, 0x21, 0x56, 0x03, 0x33, 0x7b, 0xb9, 0xfe, 0x6f, 0x4c, 0x55, 0xc2, 0xc1, + 0x2f, 0xbd, 0x2b, 0x6a, 0x57, 0x82, 0xf7, 0xa3, 0xf6, 0xe5, 0xdb, 0x92, 0x39, 0x49, 0x92, 0x76, + 0xb3, 0xf9, 0x33, 0x6f, 0xac, 0x80, 0xdd, 0xfa, 0x9f, 0x90, 0xed, 0x12, 0x85, 0xf0, 0x45, 0x34, + 0x23, 0xce, 0xd1, 0x5f, 0x5e, 0xff, 0x01, 0x5b, 0xca, 0x74, 0xbb, 0x08, 0x13, 0x00, 0x00 }; diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 7738a1e9..d83c7a44 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -139,6 +139,10 @@ #include "../usermods/audioreactive/audio_reactive.h" #endif +#ifdef USERMOD_WEATHER +#include "../usermods/usermod_v2_weather/usermod_v2_weather.h" +#endif + void registerUsermods() { /* @@ -265,4 +269,8 @@ void registerUsermods() #endif usermods.add(new AudioReactive()); #endif + + #ifdef USERMOD_WEATHER + usermods.add(new WeatherUsermod()); + #endif } From c51e03fbf9beabebea63a3ba42d921c0affd64a7 Mon Sep 17 00:00:00 2001 From: Ewowi Date: Wed, 10 Aug 2022 18:09:25 +0200 Subject: [PATCH 2/4] Weather Usermod: implement blaz recommendations --- .../usermod_v2_weather/usermod_v2_weather.h | 158 +++++++----------- wled00/FX.h | 2 +- 2 files changed, 63 insertions(+), 97 deletions(-) diff --git a/usermods/usermod_v2_weather/usermod_v2_weather.h b/usermods/usermod_v2_weather/usermod_v2_weather.h index 6927dcc7..fed5f76a 100644 --- a/usermods/usermod_v2_weather/usermod_v2_weather.h +++ b/usermods/usermod_v2_weather/usermod_v2_weather.h @@ -4,12 +4,6 @@ #define FX_MODE_2DWEATHER 185 // can we do this here? Can we also increase modeCount here? -#define pushLoopIndex 0 -#define tempsIndex 1 -#define timesIndex 2 -#define minTempIndex 3 -#define maxTempIndex 4 - //utility function, move somewhere else??? void epochToString(time_t time, char *timeString) { tmElements_t tm; @@ -17,21 +11,18 @@ void epochToString(time_t time, char *timeString) { sprintf(timeString, "%04d-%02d-%02d %02d:%02d:%02d", tm.Year + 1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second); } +//globals used in effect +static uint32_t pushLoop = 0; //effect pushes loop to execute. might be interesting for audioreactive too +static uint8_t units = 1; //metric (celsius) is default. (Standard=Kelvin, Imperial is Fahrenheit) +static float temps[100]; //array of temperatures +static time_t times[100]; //array of corresponding times +static float minTemp = 0; //config var +static float maxTemp = 40; //config var + //effect function uint16_t mode_2DWeather(void) { - //or use um_data or make vars global static ...??? Looking at the amount of extra code, global static cleaner? - um_data_t *um_data; - if (!usermods.getUMData(&um_data, USERMOD_ID_WEATHER)) { - SEGMENT.fill(SEGCOLOR(0)); - return FRAMETIME; - } - uint32_t *pushLoop = (uint32_t*)um_data->u_data[pushLoopIndex]; //pointer as it is set here - float *temps = (float*)um_data->u_data[tempsIndex]; - time_t *times = (time_t*)um_data->u_data[timesIndex]; - float minTemp = *(float*)um_data->u_data[minTempIndex]; - float maxTemp = *(float*)um_data->u_data[maxTempIndex]; - *pushLoop = millis(); //will be reset to 0 in usermod loop + pushLoop = millis(); //will be reset to 0 in usermod loop SEGMENT.fadeToBlackBy(10); @@ -95,37 +86,18 @@ static const char _data_FX_MODE_2DWEATHER[] PROGMEM = "Weather@;!;!;pal=54,2d"; class WeatherUsermod : public Usermod { private: unsigned long lastTime = 0; //will be used to download new forecast every hour - uint32_t pushLoop = 0; //effect pushes loop to execute. might be interesting for audioreactive too static const char _name[]; //usermod name //config variables - String apiKey = "get one from OpenWeatherMap.org"; - uint8_t units = 1; //metric (celsius) is default. (Standard=Kelvin, Imperial is Fahrenheit) - float minTemp = 0; - float maxTemp = 40; - - float temps[100]; //array of temperatures - time_t times[100]; //array of corresponding times + String apiKey = ""; + const char *cityName; + const char *countryName; public: void setup() { - um_data = new um_data_t; - um_data->u_size = 5; - um_data->u_type = new um_types_t[um_data->u_size]; - um_data->u_data = new void*[um_data->u_size]; - um_data->u_data[pushLoopIndex] = &pushLoop; - um_data->u_type[pushLoopIndex] = UMT_UINT32; - um_data->u_data[tempsIndex] = temps; - um_data->u_type[tempsIndex] = UMT_FLOAT_ARR; - um_data->u_data[timesIndex] = times; - um_data->u_type[timesIndex] = UMT_UINT32_ARR; - um_data->u_data[minTempIndex] = &minTemp; - um_data->u_type[minTempIndex] = UMT_FLOAT; - um_data->u_data[maxTempIndex] = &maxTemp; - um_data->u_type[maxTempIndex] = UMT_FLOAT; - strip.addEffect(FX_MODE_2DWEATHER, &mode_2DWeather, _data_FX_MODE_2DWEATHER); + strip.addEffect(255, &mode_2DWeather, _data_FX_MODE_2DWEATHER); } void connected() { @@ -136,9 +108,16 @@ class WeatherUsermod : public Usermod { if (pushLoop > millis() - 1000 && (lastTime == 0 || millis() - lastTime > 3600 * 1000)) { lastTime = millis(); + WiFiClient client; + + char url[180]; + sprintf(url, "GET /data/2.5/forecast?lat=%f&lon=%f&appid=%s&units=%s HTTP/1.0", latitude, longitude, apiKey.c_str(), units==0?"standard":units==1?"metric":"imperial"); + #ifdef WLED_DEBUG + Serial.println(url); + #endif + //https://arduinojson.org/v6/example/http-client/ //is this the most compact way to do http get and put it in arduinojson object??? - WiFiClient client; client.setTimeout(10000); if (!client.connect("api.openweathermap.org", 80)) { @@ -146,11 +125,6 @@ class WeatherUsermod : public Usermod { return; } - Serial.println(F("Connected!")); - - char url[180]; - sprintf(url, "GET /data/2.5/forecast?lat=%f&lon=%f&appid=%s&units=%s HTTP/1.0", latitude, longitude, apiKey.c_str(), units==0?"standard":units==1?"metric":"imperial"); - Serial.println(url); // Send HTTP request client.println(url); client.println(F("Host: api.openweathermap.org")); @@ -170,7 +144,6 @@ class WeatherUsermod : public Usermod { client.stop(); return; } - Serial.println(status); // Skip HTTP headers char endOfHeaders[] = "\r\n\r\n"; @@ -200,70 +173,63 @@ class WeatherUsermod : public Usermod { JsonObject weatherDocObject = weatherDoc.as(); JsonArray list = weatherDocObject[F("list")]; + JsonObject city = weatherDocObject["city"]; + cityName = city["name"]; + countryName = city["country"]; uint8_t i = 0; for (JsonObject listElement: list) { - JsonObject main = listElement["main"]; - - char timeString[64]; - epochToString(listElement["dt"], timeString); - Serial.print(timeString); - - float temp = main["temp"]; - Serial.print(" temp "); - Serial.print(temp); - - temps[i%100] = temp; times[i%100] = listElement["dt"]; - JsonObject city = weatherDocObject["city"]; - Serial.print(" city "); - Serial.print((const char *)city["name"]); - Serial.print(" - "); - Serial.print((const char *)city["country"]); - Serial.print(" sunrise "); - char sunriseString[64]; - epochToString(city["sunrise"], sunriseString); - Serial.print(sunriseString); + JsonObject main = listElement["main"]; + temps[i%100] = main["temp"]; - Serial.print(" localtime "); - char localTimeString[64]; - epochToString(localTime, localTimeString); - Serial.print(localTimeString); + #ifdef WLED_DEBUG + char timeString[64]; + epochToString(listElement["dt"], timeString); + Serial.print(timeString); + + Serial.print(" temp "); + Serial.print(main["temp"]); + + Serial.print(" city "); + Serial.print(cityName); + Serial.print(" - "); + Serial.print(countryName); + + Serial.print(" sunrise "); + char sunriseString[64]; + epochToString(city["sunrise"], sunriseString); + Serial.print(sunriseString); + + Serial.print(" localtime "); + char localTimeString[64]; + epochToString(localTime, localTimeString); + Serial.print(localTimeString); + + Serial.println(); + #endif - Serial.println(); i++; } } pushLoop = 0; } - bool getUMData(um_data_t **data) //do not forget this or um_data doesn't work!! Can it be moved to superclass? - { - if (!data) return false; // no pointer provided by caller or not enabled -> exit - *data = um_data; - return true; - } - - /* * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. * Below it is shown how this could be used for e.g. a light sensor */ - /* void addToJsonInfo(JsonObject& root) { - int reading = 20; - //this code adds "u":{"Light":[20," lux"]} to the info object JsonObject user = root["u"]; if (user.isNull()) user = root.createNestedObject("u"); - JsonArray lightArr = user.createNestedArray("Light"); //name - lightArr.add(reading); //value - lightArr.add(" lux"); //unit + JsonArray infoArr = user.createNestedArray(FPSTR(_name)); + infoArr.add(cityName); //value + infoArr.add(countryName); //unit } - */ /* @@ -290,10 +256,10 @@ class WeatherUsermod : public Usermod { void addToConfig(JsonObject& root) { JsonObject top = root.createNestedObject(FPSTR(_name)); - top["apiKey"] = apiKey; - top["units"] = units; - top["minTemp"] = minTemp; - top["maxTemp"] = maxTemp; + top[F("apiKey")] = apiKey; + top[F("units")] = units; + top[F("minTemp")] = minTemp; + top[F("maxTemp")] = maxTemp; } @@ -303,10 +269,10 @@ class WeatherUsermod : public Usermod { bool configComplete = !top.isNull(); - configComplete &= getJsonValue(top["apiKey"], apiKey); - configComplete &= getJsonValue(top["units"], units); - configComplete &= getJsonValue(top["minTemp"], minTemp); - configComplete &= getJsonValue(top["maxTemp"], maxTemp); + configComplete &= getJsonValue(top[F("apiKey")], apiKey); + configComplete &= getJsonValue(top[F("units")], units); + configComplete &= getJsonValue(top[F("minTemp")], minTemp); + configComplete &= getJsonValue(top[F("maxTemp")], maxTemp); // * Return true in case the config values returned from Usermod Settings were complete, or false if you'd like WLED to save your defaults to disk (so any missing values are editable in Usermod Settings) return configComplete; diff --git a/wled00/FX.h b/wled00/FX.h index acc9582b..d3c7733c 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -378,7 +378,7 @@ // #define FX_MODE_2DAKEMI 186 // audio enhanced //#define FX_MODE_CUSTOMEFFECT 187 //WLEDSR Custom Effects - #define MODE_COUNT 186 + #define MODE_COUNT 185 #endif typedef enum mapping1D2D { From 1e53b2bcf52e00eaf1034b031cb4b6ceb557ea19 Mon Sep 17 00:00:00 2001 From: Ewowi Date: Thu, 11 Aug 2022 18:15:51 +0200 Subject: [PATCH 3/4] Weather usermod, more blaz recommendations - add WEATHER_DEBUG - move globals to class statics => create forwards, move effect to end of file, refer to it as :: - move http get to httpGet utility function - add errorMessage variable and show in Info - increase JSON doc from 20000 to 24000 bytes --- .../usermod_v2_weather/usermod_v2_weather.h | 339 +++++++++--------- 1 file changed, 176 insertions(+), 163 deletions(-) diff --git a/usermods/usermod_v2_weather/usermod_v2_weather.h b/usermods/usermod_v2_weather/usermod_v2_weather.h index fed5f76a..01d35a9a 100644 --- a/usermods/usermod_v2_weather/usermod_v2_weather.h +++ b/usermods/usermod_v2_weather/usermod_v2_weather.h @@ -2,7 +2,12 @@ #include "wled.h" -#define FX_MODE_2DWEATHER 185 // can we do this here? Can we also increase modeCount here? +// #define WEATHER_DEBUG + +//forward declarations as usermod class needs them +uint16_t mode_2DWeather(void); +//would like _data_FX_MODE_2DWEATHER after effect declaration but due to class static vars not possible... +static const char _data_FX_MODE_2DWEATHER[] PROGMEM = "Weather@;!;!;pal=54,2d"; //temperature palette //utility function, move somewhere else??? void epochToString(time_t time, char *timeString) { @@ -11,92 +16,61 @@ void epochToString(time_t time, char *timeString) { sprintf(timeString, "%04d-%02d-%02d %02d:%02d:%02d", tm.Year + 1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second); } -//globals used in effect -static uint32_t pushLoop = 0; //effect pushes loop to execute. might be interesting for audioreactive too -static uint8_t units = 1; //metric (celsius) is default. (Standard=Kelvin, Imperial is Fahrenheit) -static float temps[100]; //array of temperatures -static time_t times[100]; //array of corresponding times -static float minTemp = 0; //config var -static float maxTemp = 40; //config var - -//effect function -uint16_t mode_2DWeather(void) { - - pushLoop = millis(); //will be reset to 0 in usermod loop - - SEGMENT.fadeToBlackBy(10); - - float currentTemp = 0; - // time_t currentTime = 0; - - for (int x=0; x= localTime) { - color = RED; - currentTemp = map(localTime, times[x%100], times[(x+1)%100], temps[x%100] * 1000, temps[(x+1)%100] * 1000) / 1000.0; - // currentTime = localTime; - } - else - color = ColorFromPalette(SEGPALETTE, map((uint8_t)temps[x%100], 0, 40, 0, 255), 255, LINEARBLEND); - - for (int y=0; y(); + JsonArray list = weatherDocObject[F("list")]; + JsonObject city = weatherDocObject["city"]; + strcat(errorMessage, city["name"]); //api succesfull + strcat(errorMessage, city["country"]); - // Check HTTP status - char status[32] = {0}; - client.readBytesUntil('\r', status, sizeof(status)); - if (strcmp(status, "HTTP/1.1 200 OK") != 0) { - Serial.print(F("Unexpected response: ")); - Serial.println(status); - client.stop(); - return; - } + uint8_t i = 0; + for (JsonObject listElement: list) { + times[i%100] = listElement["dt"]; - // Skip HTTP headers - char endOfHeaders[] = "\r\n\r\n"; - if (!client.find(endOfHeaders)) { - Serial.println(F("Invalid response")); - client.stop(); - return; - } + JsonObject main = listElement["main"]; + temps[i%100] = main["temp"]; - // Allocate the JSON document - // Use arduinojson.org/v6/assistant to compute the capacity. - // const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60; - DynamicJsonDocument weatherDoc(20000); + #ifdef WEATHER_DEBUG + char timeString[64]; + epochToString(listElement["dt"], timeString); + Serial.print(timeString); - // Parse JSON object - DeserializationError error = deserializeJson(weatherDoc, client); - if (error) { - Serial.print(F("deserializeJson() failed: ")); - Serial.println(error.f_str()); - client.stop(); - return; + Serial.print(" temp "); + Serial.print(temps[i%100]); + + Serial.print(" city "); + Serial.print(errorMessage); + + Serial.print(" sunrise "); + char sunriseString[64]; + epochToString(city["sunrise"], sunriseString); + Serial.print(sunriseString); + + Serial.print(" localtime "); + char localTimeString[64]; + epochToString(localTime, localTimeString); + Serial.print(localTimeString); + + Serial.println(); + #endif + + i++; + } + } } // Disconnect client.stop(); - - JsonObject weatherDocObject = weatherDoc.as(); - JsonArray list = weatherDocObject[F("list")]; - JsonObject city = weatherDocObject["city"]; - cityName = city["name"]; - countryName = city["country"]; - - uint8_t i = 0; - for (JsonObject listElement: list) { - times[i%100] = listElement["dt"]; - - JsonObject main = listElement["main"]; - temps[i%100] = main["temp"]; - - #ifdef WLED_DEBUG - char timeString[64]; - epochToString(listElement["dt"], timeString); - Serial.print(timeString); - - Serial.print(" temp "); - Serial.print(main["temp"]); - - Serial.print(" city "); - Serial.print(cityName); - Serial.print(" - "); - Serial.print(countryName); - - Serial.print(" sunrise "); - char sunriseString[64]; - epochToString(city["sunrise"], sunriseString); - Serial.print(sunriseString); - - Serial.print(" localtime "); - char localTimeString[64]; - epochToString(localTime, localTimeString); - Serial.print(localTimeString); - - Serial.println(); - #endif - - i++; - } } pushLoop = 0; } @@ -227,8 +169,8 @@ class WeatherUsermod : public Usermod { if (user.isNull()) user = root.createNestedObject("u"); JsonArray infoArr = user.createNestedArray(FPSTR(_name)); - infoArr.add(cityName); //value - infoArr.add(countryName); //unit + infoArr.add(errorMessage); //value + // infoArr.add(""); //unit } @@ -286,7 +228,7 @@ class WeatherUsermod : public Usermod { oappend(SET_F("addOption(dd,'Fahrenheit',2);")); oappend(SET_F("addInfo('WeatherUserMod:units',1,'Set time and location in time settings');")); oappend(SET_F("addInfo('WeatherUserMod:apiKey',1,'Create acount on openweathermap.org and copy the key');")); - oappend(SET_F("addInfo('WeatherUserMod:minTemp',1,'Reboot if you change apiKey to reload forecast');")); + oappend(SET_F("addInfo('WeatherUserMod:minTemp',1,'Changing values: Reboot to (re)load forecast');")); } /* @@ -312,3 +254,74 @@ class WeatherUsermod : public Usermod { // strings to reduce flash memory usage (used more than twice) const char WeatherUsermod::_name[] PROGMEM = "WeatherUserMod"; + +//define class static variables used in weather effect +String WeatherUsermod::apiKey = ""; //config var +float WeatherUsermod::minTemp = 0; //config var +float WeatherUsermod::maxTemp = 40; //config var +uint8_t WeatherUsermod::units = 1; //config var: metric (celsius) is default. (Standard=Kelvin, Imperial is Fahrenheit) +uint32_t WeatherUsermod::pushLoop = 0; +float WeatherUsermod::temps[100]; //array of temperatures +time_t WeatherUsermod::times[100]; //array of corresponding times + +//effect function +uint16_t mode_2DWeather(void) { + + WeatherUsermod::pushLoop = millis(); //will be reset to 0 in usermod loop + + SEGMENT.fadeToBlackBy(10); + + float currentTemp = 0; + // time_t currentTime = 0; + + for (int x=0; x= localTime) { + color = RED; + currentTemp = map(localTime, WeatherUsermod::times[x%100], WeatherUsermod::times[(x+1)%100], WeatherUsermod::temps[x%100] * 1000, WeatherUsermod::temps[(x+1)%100] * 1000) / 1000.0; + // currentTime = localTime; + } + else + color = ColorFromPalette(SEGPALETTE, map((uint8_t)WeatherUsermod::temps[x%100], 0, 40, 0, 255), 255, LINEARBLEND); + + for (int y=0; y Date: Fri, 12 Aug 2022 11:52:10 +0200 Subject: [PATCH 4/4] WeatherMod: move class statics back to globals using prefix --- .../usermod_v2_weather/usermod_v2_weather.h | 195 +++++++++--------- 1 file changed, 100 insertions(+), 95 deletions(-) diff --git a/usermods/usermod_v2_weather/usermod_v2_weather.h b/usermods/usermod_v2_weather/usermod_v2_weather.h index 01d35a9a..850ea850 100644 --- a/usermods/usermod_v2_weather/usermod_v2_weather.h +++ b/usermods/usermod_v2_weather/usermod_v2_weather.h @@ -4,9 +4,93 @@ // #define WEATHER_DEBUG -//forward declarations as usermod class needs them -uint16_t mode_2DWeather(void); -//would like _data_FX_MODE_2DWEATHER after effect declaration but due to class static vars not possible... +//declare weathermod global variables (always precede with weather_ (psuedo class static variables) +static uint32_t usermods_pushLoop = 0; //effect pushes loop to execute. might be interesting for audioreactive too +static uint8_t weather_units = 1; //config var metric (celsius) is default. (Standard=Kelvin, Imperial is Fahrenheit) +static float weather_minTemp = 0; //config var +static float weather_maxTemp = 40; //config var +static float weather_temps[100]; //array of temperatures +static time_t weather_times[100]; //array of corresponding times + +//effect function +uint16_t mode_2DWeather(void) { + + usermods_pushLoop = millis(); //will be reset to 0 in usermod loop + + SEGMENT.fadeToBlackBy(10); + + float currentTemp = 0; + // time_t currentTime = 0; + + for (int x=0; x= localTime) { + color = RED; + currentTemp = map(localTime, weather_times[x%100], weather_times[(x+1)%100], weather_temps[x%100] * 1000, weather_temps[(x+1)%100] * 1000) / 1000.0; + // currentTime = localTime; + } + else + color = ColorFromPalette(SEGPALETTE, map((uint8_t)weather_temps[x%100], 0, 40, 0, 255), 255, LINEARBLEND); + + for (int y=0; y millis() - 1000 && (lastTime == 0 || millis() - lastTime > 3600 * 1000)) { + if (usermods_pushLoop > millis() - 1000 && (lastTime == 0 || millis() - lastTime > 3600 * 1000)) { lastTime = millis(); WiFiClient client; char url[180]; - sprintf(url, "GET /data/2.5/forecast?lat=%f&lon=%f&appid=%s&units=%s HTTP/1.0", latitude, longitude, apiKey.c_str(), units==0?"standard":units==1?"metric":"imperial"); + sprintf(url, "GET /data/2.5/forecast?lat=%f&lon=%f&appid=%s&units=%s HTTP/1.0", latitude, longitude, apiKey.c_str(), weather_units==0?"standard":weather_units==1?"metric":"imperial"); #ifdef WEATHER_DEBUG Serial.println(url); #endif @@ -93,7 +170,6 @@ class WeatherUsermod : public Usermod { httpGet(client, url, errorMessage); if (strcmp(errorMessage, "") == 0) { - Serial.println("after httpget"); // Allocate the JSON document // Use arduinojson.org/v6/assistant to compute the capacity. // const size_t capacity = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2) + 60; @@ -117,10 +193,10 @@ class WeatherUsermod : public Usermod { uint8_t i = 0; for (JsonObject listElement: list) { - times[i%100] = listElement["dt"]; + weather_times[i%100] = listElement["dt"]; JsonObject main = listElement["main"]; - temps[i%100] = main["temp"]; + weather_temps[i%100] = main["temp"]; #ifdef WEATHER_DEBUG char timeString[64]; @@ -128,7 +204,7 @@ class WeatherUsermod : public Usermod { Serial.print(timeString); Serial.print(" temp "); - Serial.print(temps[i%100]); + Serial.print(weather_temps[i%100]); Serial.print(" city "); Serial.print(errorMessage); @@ -155,7 +231,7 @@ class WeatherUsermod : public Usermod { client.stop(); } - pushLoop = 0; + usermods_pushLoop = 0; } /* @@ -199,9 +275,9 @@ class WeatherUsermod : public Usermod { { JsonObject top = root.createNestedObject(FPSTR(_name)); top[F("apiKey")] = apiKey; - top[F("units")] = units; - top[F("minTemp")] = minTemp; - top[F("maxTemp")] = maxTemp; + top[F("units")] = weather_units; + top[F("minTemp")] = weather_minTemp; + top[F("maxTemp")] = weather_maxTemp; } @@ -212,9 +288,9 @@ class WeatherUsermod : public Usermod { bool configComplete = !top.isNull(); configComplete &= getJsonValue(top[F("apiKey")], apiKey); - configComplete &= getJsonValue(top[F("units")], units); - configComplete &= getJsonValue(top[F("minTemp")], minTemp); - configComplete &= getJsonValue(top[F("maxTemp")], maxTemp); + configComplete &= getJsonValue(top[F("units")], weather_units); + configComplete &= getJsonValue(top[F("minTemp")], weather_minTemp); + configComplete &= getJsonValue(top[F("maxTemp")], weather_maxTemp); // * Return true in case the config values returned from Usermod Settings were complete, or false if you'd like WLED to save your defaults to disk (so any missing values are editable in Usermod Settings) return configComplete; @@ -254,74 +330,3 @@ class WeatherUsermod : public Usermod { // strings to reduce flash memory usage (used more than twice) const char WeatherUsermod::_name[] PROGMEM = "WeatherUserMod"; - -//define class static variables used in weather effect -String WeatherUsermod::apiKey = ""; //config var -float WeatherUsermod::minTemp = 0; //config var -float WeatherUsermod::maxTemp = 40; //config var -uint8_t WeatherUsermod::units = 1; //config var: metric (celsius) is default. (Standard=Kelvin, Imperial is Fahrenheit) -uint32_t WeatherUsermod::pushLoop = 0; -float WeatherUsermod::temps[100]; //array of temperatures -time_t WeatherUsermod::times[100]; //array of corresponding times - -//effect function -uint16_t mode_2DWeather(void) { - - WeatherUsermod::pushLoop = millis(); //will be reset to 0 in usermod loop - - SEGMENT.fadeToBlackBy(10); - - float currentTemp = 0; - // time_t currentTime = 0; - - for (int x=0; x= localTime) { - color = RED; - currentTemp = map(localTime, WeatherUsermod::times[x%100], WeatherUsermod::times[(x+1)%100], WeatherUsermod::temps[x%100] * 1000, WeatherUsermod::temps[(x+1)%100] * 1000) / 1000.0; - // currentTime = localTime; - } - else - color = ColorFromPalette(SEGPALETTE, map((uint8_t)WeatherUsermod::temps[x%100], 0, 40, 0, 255), 255, LINEARBLEND); - - for (int y=0; y