Compare commits
7 Commits
0cf2e5ca90
...
4d810783fc
| Author | SHA1 | Date | |
|---|---|---|---|
| 4d810783fc | |||
| feb26d7269 | |||
| 3dfd6c82fe | |||
| 244455909d | |||
| f53f557a6a | |||
| e1df24633a | |||
| 4543cf1e09 |
13
.gitignore
vendored
13
.gitignore
vendored
@@ -65,4 +65,15 @@ log.txt
|
|||||||
modules.order
|
modules.order
|
||||||
Module.symvers
|
Module.symvers
|
||||||
Mkfile.old
|
Mkfile.old
|
||||||
dkms.conf
|
dkms.conf
|
||||||
|
|
||||||
|
# Python
|
||||||
|
venv
|
||||||
|
.venv
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Local backup
|
||||||
|
*.*_
|
||||||
|
*.*bak*
|
||||||
|
|||||||
26
include/diagnosis.h
Normal file
26
include/diagnosis.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef DIAGNOSIS_H
|
||||||
|
#define DIAGNOSIS_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "led_matrix.h"
|
||||||
|
#include "udp_logger.h"
|
||||||
|
|
||||||
|
class Diagnosis
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Diagnosis(); // constructor
|
||||||
|
Diagnosis(UDPLogger *logger, LEDMatrix *matrix); // constructor
|
||||||
|
|
||||||
|
String handle_command(const String &command);
|
||||||
|
String print_device_info();
|
||||||
|
String print_sketch_info();
|
||||||
|
String print_last_reset_details();
|
||||||
|
String print_matrix_fps();
|
||||||
|
|
||||||
|
private:
|
||||||
|
UDPLogger *_logger;
|
||||||
|
LEDMatrix * _matrix;
|
||||||
|
void print(const String &s);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DIAGNOSIS_H
|
||||||
@@ -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 */
|
||||||
@@ -79,8 +79,8 @@ private:
|
|||||||
UDPLogger *_logger;
|
UDPLogger *_logger;
|
||||||
uint8_t _gameState = 0;
|
uint8_t _gameState = 0;
|
||||||
uint8_t _numBots = 0;
|
uint8_t _numBots = 0;
|
||||||
uint8_t _playerMovement[PLAYER_AMOUNT] = {0};
|
uint8_t _playerMovement[PLAYER_AMOUNT];
|
||||||
Coords _paddles[PLAYER_AMOUNT][PADDLE_WIDTH] = {0};
|
Coords _paddles[PLAYER_AMOUNT][PADDLE_WIDTH];
|
||||||
Coords _ball = {0, 0};
|
Coords _ball = {0, 0};
|
||||||
Coords _ball_old = {0, 0};
|
Coords _ball_old = {0, 0};
|
||||||
int _ballMovement[2] = {0, 0};
|
int _ballMovement[2] = {0, 0};
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ private:
|
|||||||
uint8_t _userDirection = 0;
|
uint8_t _userDirection = 0;
|
||||||
uint8_t _gameState = 0;
|
uint8_t _gameState = 0;
|
||||||
Coords _head = {0, 0};
|
Coords _head = {0, 0};
|
||||||
Coords _tail[MAX_TAIL_LENGTH] = {0};
|
Coords _tail[MAX_TAIL_LENGTH];
|
||||||
Coords _food = {0, 0};
|
Coords _food = {0, 0};
|
||||||
unsigned long _lastDrawUpdate = 0;
|
unsigned long _lastDrawUpdate = 0;
|
||||||
unsigned long _lastButtonClick = 0;
|
unsigned long _lastButtonClick = 0;
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -12,15 +12,16 @@
|
|||||||
default_envs = nodemcuv2
|
default_envs = nodemcuv2
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
platform = espressif8266
|
platform = espressif8266@2.6.3
|
||||||
board = nodemcuv2
|
board = nodemcuv2
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
lib_deps =
|
||||||
adafruit/Adafruit BusIO@^1.15.0
|
|
||||||
adafruit/Adafruit NeoMatrix@^1.3.0
|
|
||||||
adafruit/Adafruit NeoPixel@^1.11.0
|
|
||||||
densaugeo/base64@^1.4.0
|
densaugeo/base64@^1.4.0
|
||||||
|
fastled/FastLED@3.7.0
|
||||||
|
marcmerlin/FastLED NeoMatrix@^1.2
|
||||||
tzapu/WiFiManager@^0.16.0
|
tzapu/WiFiManager@^0.16.0
|
||||||
|
build_flags =
|
||||||
|
-DFASTLED_ESP8266_RAW_PIN_ORDER
|
||||||
|
|
||||||
[env:nodemcuv2]
|
[env:nodemcuv2]
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
|
|||||||
13
scripts/http_diagnosis.py
Normal file
13
scripts/http_diagnosis.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import requests
|
||||||
|
|
||||||
|
r = requests.get("http://wordclock.local/cmd?diag=reset_info")
|
||||||
|
print(r.status_code)
|
||||||
|
print(r.text)
|
||||||
|
|
||||||
|
r = requests.get("http://wordclock.local/cmd?diag=sketch_info")
|
||||||
|
print(r.status_code)
|
||||||
|
print(r.text)
|
||||||
|
|
||||||
|
r = requests.get("http://wordclock.local/cmd?diag=device_info")
|
||||||
|
print(r.status_code)
|
||||||
|
print(r.text)
|
||||||
@@ -4,15 +4,17 @@ import queue
|
|||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
LOG_PATH = Path("C:/temp/wordclock_log.txt")
|
||||||
|
|
||||||
def setup_logging():
|
def setup_logging():
|
||||||
FORMAT = "%(asctime)s %(message)s"
|
FORMAT = "%(asctime)s %(message)s"
|
||||||
logging.basicConfig(format=FORMAT, level=logging.INFO)
|
logging.basicConfig(format=FORMAT, level=logging.INFO)
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
#handler = logging.StreamHandler(sys.stdout)
|
handler = logging.FileHandler(LOG_PATH)
|
||||||
#handler.setLevel(logging.INFO)
|
handler.setLevel(logging.INFO)
|
||||||
#logger.addHandler(handler)
|
logger.addHandler(handler)
|
||||||
return logger
|
return logger
|
||||||
|
|
||||||
|
|
||||||
@@ -42,33 +44,9 @@ mreq = struct.pack("4s4s", group, socket.inet_aton(get_ip_address()))
|
|||||||
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
|
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
|
||||||
|
|
||||||
logger.info("Ready")
|
logger.info("Ready")
|
||||||
saveCounter = 0
|
|
||||||
|
|
||||||
buffer = queue.Queue(20)
|
|
||||||
|
|
||||||
# Receive/respond loop
|
# Receive/respond loop
|
||||||
while True:
|
while True:
|
||||||
data, address = sock.recvfrom(1024)
|
data, address = sock.recvfrom(1024)
|
||||||
data_str = data.decode("utf-8").strip()
|
data_str = data.decode("utf-8").strip()
|
||||||
logger.info(data_str)
|
logger.info(data_str)
|
||||||
data_str = datetime.now().strftime("%b-%d-%Y_%H%M%S") + ": " + data_str
|
|
||||||
buffer.put(data_str)
|
|
||||||
if buffer.full():
|
|
||||||
buffer.get()
|
|
||||||
|
|
||||||
if "NTP-Update not successful" in data_str or "Start program" in data_str:
|
|
||||||
f = open("log.txt", "a")
|
|
||||||
while not buffer.empty():
|
|
||||||
f.write(buffer.get())
|
|
||||||
f.write("\n")
|
|
||||||
f.close()
|
|
||||||
saveCounter = 20
|
|
||||||
|
|
||||||
if saveCounter > 0:
|
|
||||||
f = open("log.txt", "a")
|
|
||||||
f.write(data_str)
|
|
||||||
f.write("\n")
|
|
||||||
if saveCounter == 1:
|
|
||||||
f.write("\n")
|
|
||||||
f.close()
|
|
||||||
saveCounter -= 1
|
|
||||||
|
|||||||
BIN
scripts/requirements.txt
Normal file
BIN
scripts/requirements.txt
Normal file
Binary file not shown.
93
src/connectivity/diagnosis.cpp
Normal file
93
src/connectivity/diagnosis.cpp
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#include "diagnosis.h"
|
||||||
|
|
||||||
|
Diagnosis::Diagnosis()
|
||||||
|
{
|
||||||
|
_logger = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Diagnosis::Diagnosis(UDPLogger *logger, LEDMatrix *matrix) // constructor
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_matrix = matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Diagnosis::handle_command(const String &command)
|
||||||
|
{
|
||||||
|
if (command == "device_info")
|
||||||
|
{
|
||||||
|
return print_device_info();
|
||||||
|
}
|
||||||
|
else if (command == "sketch_info")
|
||||||
|
{
|
||||||
|
return print_sketch_info();
|
||||||
|
}
|
||||||
|
else if (command == "reset_info")
|
||||||
|
{
|
||||||
|
return print_last_reset_details();
|
||||||
|
}
|
||||||
|
else if (command == "matrix_fps")
|
||||||
|
{
|
||||||
|
return print_matrix_fps();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Handle unknown command
|
||||||
|
String unknown_command = "Diagnosis: Unknown command!\n";
|
||||||
|
print(unknown_command);
|
||||||
|
return unknown_command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String Diagnosis::print_device_info()
|
||||||
|
{
|
||||||
|
// Retrieve and print device information
|
||||||
|
String device_info = "Device Information:\n";
|
||||||
|
device_info += "Chip ID: " + String(ESP.getChipId()) + "\n";
|
||||||
|
device_info += "Flash Chip ID: " + String(ESP.getFlashChipId()) + "\n";
|
||||||
|
device_info += "Flash Chip Size: " + String(ESP.getFlashChipSize()) + " bytes\n";
|
||||||
|
device_info += "Free Heap Size: " + String(ESP.getFreeHeap()) + " bytes\n";
|
||||||
|
device_info += "Free Sketch Space: " + String(ESP.getFreeSketchSpace()) + " bytes\n";
|
||||||
|
device_info += "SDK Version: " + String(ESP.getSdkVersion()) + "\n";
|
||||||
|
print(device_info);
|
||||||
|
return device_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Diagnosis::print_sketch_info()
|
||||||
|
{
|
||||||
|
// Retrieve and print sketch information
|
||||||
|
String sketch_info = "Sketch Information:\n";
|
||||||
|
sketch_info += "Sketch Size: " + String(ESP.getSketchSize()) + " bytes\n";
|
||||||
|
sketch_info += "Sketch MD5: " + String(ESP.getSketchMD5()) + "\n";
|
||||||
|
print(sketch_info);
|
||||||
|
return sketch_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Diagnosis::print_last_reset_details()
|
||||||
|
{
|
||||||
|
// Retrieve and print last reset details
|
||||||
|
String reset_info = "Last Reset Details:\n";
|
||||||
|
reset_info += "Reset Reason: " + String(ESP.getResetReason()) + "\n";
|
||||||
|
reset_info += "Reset Info: " + String(ESP.getResetInfo()) + "\n";
|
||||||
|
print(reset_info);
|
||||||
|
return reset_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Diagnosis::print_matrix_fps()
|
||||||
|
{
|
||||||
|
// Retrieve and print matrix FPS
|
||||||
|
String matrix_fps = "Matrix FPS: " + String(_matrix->get_fps()) + "\n";
|
||||||
|
print(matrix_fps);
|
||||||
|
return matrix_fps;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Diagnosis::print(const String &s)
|
||||||
|
{
|
||||||
|
if (_logger != nullptr)
|
||||||
|
{
|
||||||
|
_logger->log_string(s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.println(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
#include "udp_logger.h"
|
#include "udp_logger.h"
|
||||||
|
|
||||||
UDPLogger::UDPLogger()
|
UDPLogger::UDPLogger() {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
UDPLogger::UDPLogger(IPAddress interface_addr, IPAddress multicast_addr, int port, String name)
|
UDPLogger::UDPLogger(IPAddress interface_addr, IPAddress multicast_addr, int port, String name)
|
||||||
{
|
{
|
||||||
@@ -26,8 +24,10 @@ void UDPLogger::log_string(String message)
|
|||||||
delay(10);
|
delay(10);
|
||||||
}
|
}
|
||||||
message = _name + ": " + message;
|
message = _name + ": " + message;
|
||||||
|
#ifdef SERIAL_DEBUG
|
||||||
Serial.println(message);
|
Serial.println(message);
|
||||||
delay(10);
|
delay(10);
|
||||||
|
#endif /* SERIAL_DEBUG */
|
||||||
_udp.beginPacketMulticast(_multicastAddr, _port, _interfaceAddr);
|
_udp.beginPacketMulticast(_multicastAddr, _port, _interfaceAddr);
|
||||||
message.toCharArray(_packetBuffer, 100);
|
message.toCharArray(_packetBuffer, 100);
|
||||||
_udp.print(_packetBuffer);
|
_udp.print(_packetBuffer);
|
||||||
|
|||||||
@@ -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
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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 = "{";
|
||||||
|
|||||||
Reference in New Issue
Block a user