Use FastLED instead of NeoMatrix.

This commit is contained in:
2024-07-21 19:26:56 +02:00
parent e1df24633a
commit f53f557a6a
4 changed files with 149 additions and 128 deletions

View File

@@ -1,24 +1,28 @@
#ifndef LEDMATRIX_H #ifndef LEDMATRIX_H
#define LEDMATRIX_H #define LEDMATRIX_H
#ifndef FASTLED_INTERNAL
#define FASTLED_INTERNAL
#endif
#include <Arduino.h> #include <Arduino.h>
#include <Adafruit_GFX.h> #include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h> #include <FastLED_NeoMatrix.h>
#include "wordclock_constants.h" #include "wordclock_constants.h"
#include "udp_logger.h" #include "udp_logger.h"
#define DEFAULT_CURRENT_LIMIT 9999 #define DEFAULT_CURRENT_LIMIT 9999
extern const uint32_t colors_24bit[NUM_COLORS]; extern const uint32_t colors_24bit[NUM_COLORS];
class LEDMatrix class LEDMatrix
{ {
public: public:
LEDMatrix(Adafruit_NeoMatrix * matrix, uint8_t brightness, UDPLogger * logger); LEDMatrix(FastLED_NeoMatrix *matrix, uint8_t brightness, UDPLogger *logger);
static uint16_t color_24_to_16bit(uint32_t color24bit); static uint16_t color_24_to_16bit(uint32_t color24bit);
static uint32_t color_24bit(uint8_t r, uint8_t g, uint8_t b); static uint32_t color_24bit(uint8_t r, uint8_t g, uint8_t b);
static uint32_t interpolate_color_24bit(uint32_t color1, uint32_t color2, float factor); static uint32_t interpolate_color_24bit(uint32_t color1, uint32_t color2, float factor);
static uint32_t wheel(uint8_t WheelPos); static uint32_t wheel(uint8_t WheelPos);
uint16_t get_fps(void);
void draw_on_matrix_instant(); void draw_on_matrix_instant();
void draw_on_matrix_smooth(float factor); void draw_on_matrix_smooth(float factor);
void flush(void); void flush(void);
@@ -31,17 +35,17 @@ public:
void setup_matrix(); void setup_matrix();
private: private:
Adafruit_NeoMatrix * _neomatrix; FastLED_NeoMatrix *_neomatrix;
UDPLogger * _logger; UDPLogger *_logger;
uint8_t _brightness; uint8_t _brightness;
uint16_t _current_limit; uint16_t _current_limit;
// target representation of matrix as 2D array // target representation of matrix as 2D array
uint32_t _target_grid[MATRIX_HEIGHT][MATRIX_WIDTH] = {0}; uint32_t _target_grid[MATRIX_HEIGHT][MATRIX_WIDTH];
// current representation of matrix as 2D array // current representation of matrix as 2D array
uint32_t _current_grid[MATRIX_HEIGHT][MATRIX_WIDTH] = {0}; uint32_t _current_grid[MATRIX_HEIGHT][MATRIX_WIDTH];
// target representation of minutes indicator LEDs // target representation of minutes indicator LEDs
uint32_t _target_minute_indicators[4] = {0, 0, 0, 0}; uint32_t _target_minute_indicators[4] = {0, 0, 0, 0};
@@ -53,4 +57,4 @@ private:
uint16_t _calc_estimated_led_current(uint32_t color); uint16_t _calc_estimated_led_current(uint32_t color);
}; };
#endif /* LEDMATRIX_H */ #endif /* LEDMATRIX_H */

View File

@@ -16,7 +16,7 @@
#define HTTP_PORT (80) // Standard HTTP port #define HTTP_PORT (80) // Standard HTTP port
// ESP8266 Pins // ESP8266 Pins
#define NEOPIXEL_PIN (14) // pin to which the NeoPixels are attached #define FASTLED_PIN (14) // pin to which the LEDs are attached
#define BUTTON_PIN (5) // pin to which the button is attached #define BUTTON_PIN (5) // pin to which the button is attached
// Time limits // Time limits
@@ -36,8 +36,8 @@
#define PERIOD_ANIMATION_US (200 * 1000) // 200ms #define PERIOD_ANIMATION_US (200 * 1000) // 200ms
#define PERIOD_CLOCK_UPDATE_US (1 * 1000 * 1000) // Must be 1s! Do not change! #define PERIOD_CLOCK_UPDATE_US (1 * 1000 * 1000) // Must be 1s! Do not change!
#define PERIOD_HEARTBEAT_US (1 * 1000 * 1000) // 1s #define PERIOD_HEARTBEAT_US (1 * 1000 * 1000) // 1s
#define PERIOD_MATRIX_UPDATE_US (100 * 1000) // 100ms #define PERIOD_MATRIX_UPDATE_US (33 * 1000) // 33ms
#define PERIOD_NIGHTMODE_CHECK_US (20 * 1000 * 1000) // 20s #define PERIOD_NIGHTMODE_CHECK_US (30 * 1000 * 1000) // 30s
#define PERIOD_TIME_UPDATE_US (1 * 1000 * 1000) // 1000ms #define PERIOD_TIME_UPDATE_US (1 * 1000 * 1000) // 1000ms
#define PERIOD_PONG_US (10 * 1000) // 10ms #define PERIOD_PONG_US (10 * 1000) // 10ms
#define PERIOD_SNAKE_US (50 * 1000) // 50ms #define PERIOD_SNAKE_US (50 * 1000) // 50ms
@@ -63,10 +63,12 @@
// Number of colors in colors array // Number of colors in colors array
#define NUM_COLORS (7) #define NUM_COLORS (7)
#define COLOR_ORDER GRB // WS2812B color order
// LED matrix size // LED matrix size
#define MATRIX_WIDTH (11) #define MATRIX_WIDTH (11)
#define MATRIX_HEIGHT (11) #define MATRIX_HEIGHT (11)
#define NUM_MATRIX (MATRIX_WIDTH * (MATRIX_HEIGHT + 1))
// NTP macros // NTP macros
#define BUILD_YEAR (__DATE__ + 7) // Will expand to current year at compile time as string. #define BUILD_YEAR (__DATE__ + 7) // Will expand to current year at compile time as string.

View File

@@ -21,7 +21,7 @@ const uint32_t colors_24bit[NUM_COLORS] = {
* @param mybrightness the initial brightness of the leds * @param mybrightness the initial brightness of the leds
* @param mylogger pointer to the UDPLogger object * @param mylogger pointer to the UDPLogger object
*/ */
LEDMatrix::LEDMatrix(Adafruit_NeoMatrix *matrix, uint8_t brightness, UDPLogger *logger) LEDMatrix::LEDMatrix(FastLED_NeoMatrix *matrix, uint8_t brightness, UDPLogger *logger)
{ {
_neomatrix = matrix; _neomatrix = matrix;
_brightness = brightness; _brightness = brightness;
@@ -181,6 +181,11 @@ void LEDMatrix::flush(void)
_target_minute_indicators[3] = 0; _target_minute_indicators[3] = 0;
} }
uint16_t LEDMatrix::get_fps(void)
{
return FastLED.getFPS();
}
/** /**
* @brief Write target pixels directly to leds * @brief Write target pixels directly to leds
* *

View File

@@ -23,17 +23,17 @@
#include <Arduino.h> #include <Arduino.h>
#include "wordclock_esp8266.h" #include "wordclock_esp8266.h"
#include <Adafruit_GFX.h> // https://github.com/adafruit/Adafruit-GFX-Library #include <Adafruit_GFX.h> // https://github.com/adafruit/Adafruit-GFX-Library
#include <Adafruit_NeoMatrix.h> // https://github.com/adafruit/Adafruit_NeoMatrix
#include <Adafruit_NeoPixel.h> // NeoPixel library used to run the NeoPixel LEDs: https://github.com/adafruit/Adafruit_NeoPixel
#include <base64.hpp> #include <base64.hpp>
#include <EEPROM.h> // from ESP8266 Arduino Core (automatically installed when ESP8266 was installed via Boardmanager) #include <EEPROM.h> // from ESP8266 Arduino Core (automatically installed when ESP8266 was installed via Boardmanager)
#include <ESP8266WebServer.h> #include <ESP8266WebServer.h>
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <FastLED.h>
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager WiFi Configuration Magic #include <WiFiManager.h> // https://github.com/tzapu/WiFiManager WiFi Configuration Magic
// own libraries // own libraries
#include "animation_functions.h" #include "animation_functions.h"
#include "diagnosis.h"
#include "led_matrix.h" #include "led_matrix.h"
#include "littlefs_wrapper.h" #include "littlefs_wrapper.h"
#include "ota_functions.h" #include "ota_functions.h"
@@ -49,10 +49,11 @@
// GLOBAL VARIABLES // GLOBAL VARIABLES
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
UDPLogger logger; // Global UDP logger instance UDPLogger logger; // Global UDP logger instance
Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(MATRIX_WIDTH, MATRIX_HEIGHT + 1, NEOPIXEL_PIN,
NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_ZIGZAG, CRGB leds[NUM_MATRIX]; // LED array for FastLED
NEO_GRB + NEO_KHZ800); // NeoMatrix FastLED_NeoMatrix matrix = FastLED_NeoMatrix(leds, MATRIX_WIDTH, (MATRIX_HEIGHT + 1),
LEDMatrix led_matrix = LEDMatrix(&matrix, DEFAULT_BRIGHTNESS, &logger); // NeoMatrix wrapper NEO_MATRIX_TOP + NEO_MATRIX_LEFT + NEO_MATRIX_ROWS + NEO_MATRIX_ZIGZAG);
LEDMatrix led_matrix = LEDMatrix(&matrix, DEFAULT_BRIGHTNESS, &logger); // FastLED_NeoMatrix wrapper
ESP8266WebServer webserver(HTTP_PORT); // Webserver ESP8266WebServer webserver(HTTP_PORT); // Webserver
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
@@ -78,7 +79,7 @@ static bool flg_reset_wifi_creds = false; // Used to reset stored
static float filter_factor = DEFAULT_SMOOTHING_FACTOR; // Stores smoothing factor for led transition, value of 1 represents no smoothing. static float filter_factor = DEFAULT_SMOOTHING_FACTOR; // Stores smoothing factor for led transition, value of 1 represents no smoothing.
static uint32_t main_color_clock = colors_24bit[2]; // Color of the clock and digital clock static uint32_t main_color_clock = colors_24bit[2]; // Color of the clock and digital clock
static uint8_t current_brightness = DEFAULT_BRIGHTNESS; // Current brightness of LEDs static uint8_t current_brightness = DEFAULT_BRIGHTNESS; // Current brightness of LEDs
static ClockState_en current_state = ST_CLOCK; // Stores current state static ClockState_en current_state = ST_CLOCK; // Stores current state
// Other variables // Other variables
static uint32 last_led_direct_us = 0; // Time of last direct LED command (=> fall back to normal mode after timeout) static uint32 last_led_direct_us = 0; // Time of last direct LED command (=> fall back to normal mode after timeout)
@@ -98,7 +99,6 @@ static const uint32_t period_timings[NUM_STATES] = {PERIOD_TIME_UPDATE_US, PERIO
PERIOD_ANIMATION_US, PERIOD_TETRIS_US, PERIOD_SNAKE_US, PERIOD_ANIMATION_US, PERIOD_TETRIS_US, PERIOD_SNAKE_US,
PERIOD_PONG_US, PERIOD_ANIMATION_US}; PERIOD_PONG_US, PERIOD_ANIMATION_US};
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
// SETUP // SETUP
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
@@ -118,6 +118,9 @@ void setup()
Serial.printf("Reset address: %u\n", reset_info->excvaddr); Serial.printf("Reset address: %u\n", reset_info->excvaddr);
Serial.println(); Serial.println();
// Init FastLED
FastLED.addLeds<WS2812B, FASTLED_PIN, COLOR_ORDER>(leds, NUM_MATRIX);
// Init EEPROM // Init EEPROM
EEPROM.begin(EEPROM_SIZE); EEPROM.begin(EEPROM_SIZE);
@@ -234,7 +237,6 @@ void loop()
{ {
send_heartbeat(); // send heartbeat update send_heartbeat(); // send heartbeat update
last_heartbeat_us = system_get_time(); last_heartbeat_us = system_get_time();
delay(10);
} }
if (!flg_night_mode && ((current_time_us - last_animation_step_us) > period_timings[current_state]) && if (!flg_night_mode && ((current_time_us - last_animation_step_us) > period_timings[current_state]) &&
@@ -242,7 +244,6 @@ void loop()
{ {
handle_current_state(); // handle current state handle_current_state(); // handle current state
last_animation_step_us = system_get_time(); last_animation_step_us = system_get_time();
delay(10);
} }
if ((current_time_us - last_brightness_update_us) >= PERIOD_BRIGHTNESS_UPDATE_US) if ((current_time_us - last_brightness_update_us) >= PERIOD_BRIGHTNESS_UPDATE_US)
@@ -250,14 +251,12 @@ void loop()
current_brightness = update_brightness(); // update brightness current_brightness = update_brightness(); // update brightness
logger.log_string("Brightness: " + String(((uint16_t)current_brightness * 100) / UINT8_MAX) + "%"); logger.log_string("Brightness: " + String(((uint16_t)current_brightness * 100) / UINT8_MAX) + "%");
last_brightness_update_us = system_get_time(); last_brightness_update_us = system_get_time();
delay(10);
} }
if ((current_time_us - last_matrix_update_us) >= PERIOD_MATRIX_UPDATE_US) if ((current_time_us - last_matrix_update_us) >= PERIOD_MATRIX_UPDATE_US)
{ {
update_matrix(); // update matrix update_matrix(); // update matrix
last_matrix_update_us = system_get_time(); last_matrix_update_us = system_get_time();
delay(10);
} }
if ((current_time_us - last_time_update_us) >= PERIOD_TIME_UPDATE_US) if ((current_time_us - last_time_update_us) >= PERIOD_TIME_UPDATE_US)
@@ -271,7 +270,7 @@ void loop()
ESP.restart(); ESP.restart();
} }
last_time_update_us = system_get_time(); last_time_update_us = system_get_time();
} }
if ((current_time_us - last_nightmode_check_us) >= PERIOD_NIGHTMODE_CHECK_US) if ((current_time_us - last_nightmode_check_us) >= PERIOD_NIGHTMODE_CHECK_US)
@@ -347,87 +346,87 @@ void handle_current_state()
{ {
switch (current_state) switch (current_state)
{ {
case ST_CLOCK: // state clock case ST_CLOCK: // state clock
{
if (tm_mgr.tm_state() == TM_NORMAL)
{ {
if (tm_mgr.tm_state() == TM_NORMAL) (void)show_string_on_clock(time_to_string((uint8_t)tm_mgr.hour(), (uint8_t)tm_mgr.minute()), main_color_clock);
{ draw_minute_indicator((uint8_t)tm_mgr.minute(), main_color_clock);
(void)show_string_on_clock(time_to_string((uint8_t)tm_mgr.hour(), (uint8_t)tm_mgr.minute()), main_color_clock);
draw_minute_indicator((uint8_t)tm_mgr.minute(), main_color_clock);
}
else if (tm_mgr.ntp_sync_overdue()) // if NTP sync is overdue
{
(void)show_string_on_clock(time_to_string((uint8_t)tm_mgr.hour(), (uint8_t)tm_mgr.minute()), main_color_clock);
draw_minute_indicator((uint8_t)tm_mgr.minute(), colors_24bit[6]); // in blue to indicate a network problem
}
else // if no NTP sync has been done, only show 4 blue minute indicators
{
// clear matrix
led_matrix.flush();
// Turn on minutes LEDs (blue)
led_matrix.set_min_indicator((uint8_t)0b1111, colors_24bit[6]);
led_matrix.draw_on_matrix_instant();
}
break;
} }
case ST_DICLOCK: // state diclock else if (tm_mgr.ntp_sync_overdue()) // if NTP sync is overdue
{ {
if (tm_mgr.ntp_sync_successful()) (void)show_string_on_clock(time_to_string((uint8_t)tm_mgr.hour(), (uint8_t)tm_mgr.minute()), main_color_clock);
{ draw_minute_indicator((uint8_t)tm_mgr.minute(), colors_24bit[6]); // in blue to indicate a network problem
show_digital_clock((uint8_t)tm_mgr.hour(), (uint8_t)tm_mgr.minute(), main_color_clock);
}
else
{
// clear matrix
led_matrix.flush();
// Turn on minutes LEDs (blue)
led_matrix.set_min_indicator((uint8_t)0b1111, colors_24bit[6]);
led_matrix.draw_on_matrix_instant();
}
break;
} }
case ST_SPIRAL: // state spiral else // if no NTP sync has been done, only show 4 blue minute indicators
{ {
int res = draw_spiral(false, spiral_direction, MATRIX_WIDTH - 2); // clear matrix
if ((bool)res && spiral_direction == 0) led_matrix.flush();
{ // Turn on minutes LEDs (blue)
// change spiral direction to closing (draw empty LEDs) led_matrix.set_min_indicator((uint8_t)0b1111, colors_24bit[6]);
spiral_direction = true; led_matrix.draw_on_matrix_instant();
// init spiral with new spiral direction
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
}
else if (res && spiral_direction == 1)
{
// reset spiral direction to normal drawing LEDs
spiral_direction = false;
// init spiral with new spiral direction
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
}
break;
} }
case ST_TETRIS: // state tetris break;
}
case ST_DICLOCK: // state diclock
{
if (tm_mgr.ntp_sync_successful())
{ {
tetris.loopCycle(); show_digital_clock((uint8_t)tm_mgr.hour(), (uint8_t)tm_mgr.minute(), main_color_clock);
break;
} }
case ST_SNAKE: // state snake else
{ {
snake.loopCycle(); // clear matrix
break; led_matrix.flush();
// Turn on minutes LEDs (blue)
led_matrix.set_min_indicator((uint8_t)0b1111, colors_24bit[6]);
led_matrix.draw_on_matrix_instant();
} }
case ST_PINGPONG: // state ping pong break;
}
case ST_SPIRAL: // state spiral
{
int res = draw_spiral(false, spiral_direction, MATRIX_WIDTH - 2);
if ((bool)res && spiral_direction == 0)
{ {
pong.loopCycle(); // change spiral direction to closing (draw empty LEDs)
break; spiral_direction = true;
// init spiral with new spiral direction
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
} }
case ST_HEARTS: else if (res && spiral_direction == 1)
{ {
draw_heart_animation(); // reset spiral direction to normal drawing LEDs
break; spiral_direction = false;
} // init spiral with new spiral direction
default: draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
{
break;
} }
break;
}
case ST_TETRIS: // state tetris
{
tetris.loopCycle();
break;
}
case ST_SNAKE: // state snake
{
snake.loopCycle();
break;
}
case ST_PINGPONG: // state ping pong
{
pong.loopCycle();
break;
}
case ST_HEARTS:
{
draw_heart_animation();
break;
}
default:
{
break;
}
} }
} }
@@ -503,34 +502,34 @@ void on_state_entry(uint8_t state)
filter_factor = DEFAULT_SMOOTHING_FACTOR; filter_factor = DEFAULT_SMOOTHING_FACTOR;
switch (state) switch (state)
{ {
case ST_SPIRAL: case ST_SPIRAL:
{ {
spiral_direction = 0; // Init spiral with normal drawing mode spiral_direction = 0; // Init spiral with normal drawing mode
draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1); draw_spiral(true, spiral_direction, MATRIX_WIDTH - 1);
break; break;
} }
case ST_TETRIS: case ST_TETRIS:
{ {
filter_factor = 1.0f; // no smoothing filter_factor = 1.0f; // no smoothing
tetris.ctrlStart(); tetris.ctrlStart();
break; break;
} }
case ST_SNAKE: case ST_SNAKE:
{ {
filter_factor = 1.0f; // no smoothing filter_factor = 1.0f; // no smoothing
snake.initGame(); snake.initGame();
break; break;
} }
case ST_PINGPONG: case ST_PINGPONG:
{ {
filter_factor = 1.0f; // no smoothing filter_factor = 1.0f; // no smoothing
pong.initGame(1); pong.initGame(1);
break; break;
} }
default: default:
{ {
break; break;
} }
} }
} }
@@ -546,7 +545,7 @@ void state_change(ClockState_en new_state)
set_night_mode(false); // deactivate Nightmode set_night_mode(false); // deactivate Nightmode
} }
led_matrix.flush(); // first clear matrix led_matrix.flush(); // first clear matrix
current_state = new_state; // set new state current_state = new_state; // set new state
on_state_entry((uint8_t)current_state); on_state_entry((uint8_t)current_state);
logger.log_string("State change to: " + state_names[(uint8_t)current_state]); logger.log_string("State change to: " + state_names[(uint8_t)current_state]);
@@ -691,13 +690,16 @@ void draw_main_color()
*/ */
void handle_command() void handle_command()
{ {
bool send204 = true; // flag to send 204 response
// receive command and handle accordingly // receive command and handle accordingly
#ifdef SERIAL_DEBUG
for (uint8_t i = 0; i < webserver.args(); i++) for (uint8_t i = 0; i < webserver.args(); i++)
{ {
Serial.print(webserver.argName(i)); Serial.print(webserver.argName(i));
Serial.print(F(": ")); Serial.print(F(": "));
Serial.println(webserver.arg(i)); Serial.println(webserver.arg(i));
} }
#endif /* SERIAL_DEBUG */
if (webserver.argName(0).equals("led")) // the parameter which was sent to this server is led color if (webserver.argName(0).equals("led")) // the parameter which was sent to this server is led color
{ {
@@ -798,7 +800,6 @@ void handle_command()
else if (webserver.argName(0).equals("tetris")) else if (webserver.argName(0).equals("tetris"))
{ {
String cmd_str = webserver.arg(0); String cmd_str = webserver.arg(0);
// logger.log_string("Tetris cmd via Webserver to: " + cmd_str);
if (cmd_str.equals("up")) if (cmd_str.equals("up"))
{ {
tetris.ctrlUp(); tetris.ctrlUp();
@@ -827,7 +828,6 @@ void handle_command()
else if (webserver.argName(0).equals("snake")) else if (webserver.argName(0).equals("snake"))
{ {
String cmd_str = webserver.arg(0); String cmd_str = webserver.arg(0);
// logger.log_string("Snake cmd via Webserver to: " + cmd_str);
if (cmd_str.equals("up")) if (cmd_str.equals("up"))
{ {
snake.ctrlUp(); snake.ctrlUp();
@@ -852,7 +852,6 @@ void handle_command()
else if (webserver.argName(0).equals("pong")) else if (webserver.argName(0).equals("pong"))
{ {
String cmd_str = webserver.arg(0); String cmd_str = webserver.arg(0);
// logger.log_string("Pong cmd via Webserver to: " + cmd_str);
if (cmd_str.equals("up")) if (cmd_str.equals("up"))
{ {
pong.ctrlUp(1); pong.ctrlUp(1);
@@ -866,8 +865,18 @@ void handle_command()
pong.initGame(1); pong.initGame(1);
} }
} }
else if (webserver.argName(0).equals("diag"))
{
String cmd_str = webserver.arg(0);
Diagnosis diag(&logger, &led_matrix);
webserver.send(200, "text/plain", diag.handle_command(cmd_str));
send204 = false;
}
webserver.send(204, "text/plain", "No Content"); // this page doesn't send back content --> 204 if (send204)
{
webserver.send(204, "text/plain", "No Content"); // this page doesn't send back content --> 204
}
} }
/** /**
@@ -876,6 +885,7 @@ void handle_command()
*/ */
void handle_data_request() void handle_data_request()
{ {
#ifdef SERIAL_DEBUG
// receive data request and handle accordingly // receive data request and handle accordingly
for (uint8_t i = 0; i < webserver.args(); i++) for (uint8_t i = 0; i < webserver.args(); i++)
{ {
@@ -883,7 +893,7 @@ void handle_data_request()
Serial.print(F(": ")); Serial.print(F(": "));
Serial.println(webserver.arg(i)); Serial.println(webserver.arg(i));
} }
#endif /* SERIAL_DEBUG */
if (webserver.argName(0).equals("key")) if (webserver.argName(0).equals("key"))
{ {
String message = "{"; String message = "{";