Two-part system: Python watcher tails Apache access.log live, classifies every request and broadcasts a compact UDP packet to the LAN. The ESP32 CYD receives, parses and updates the display every 400ms. No cloud, no WebSockets, no external dependencies — stdlib only on the Python side.
Apache access.log → purplnova_watcher.py → UDP Broadcast → ESP32 CYD
| Type | Color | Trigger |
|---|---|---|
VISIT | White | Normal 200/304 request |
BOT | Orange | sqlmap, nikto, python-requests UA |
PROBE | Yellow | wp-login, .env, phpMyAdmin paths |
SCAN | Orange | 8+ 404s in 15s from one IP |
ATTACK | Red | RCE attempts, shell injection, path traversal |
BLOCK | Dark Red | 403 responses |
WARN | Yellow | Known attacker IP returning |
TYPE|IP|DETAIL|TIMESTAMP ATTACK|x.x.x.x|ThinkPHP RCE|14:23:11 VISIT|x.x.x.x|GET /index.html|14:23:12 STATS|visits=12,blocks=4,bots=2,attacks=1,probes=3
If an SD card is present, every event is logged to /log_YYYYMMDD.csv.
timestamp,type,ip,detail 14:23:11,ATTACK,x.x.x.x,ThinkPHP RCE invokefunction 14:23:12,VISIT,x.x.x.x,GET /index.html
No external dependencies required (stdlib only).
purplnova_watcher.py:LOG_PATH = r"C:\xampp\apache\logs\access.log"python purplnova_watcher.pyFor autostart on Windows, drop a start_watcher.bat in shell:startup.
Board: ESP32 Dev Module · Libraries: TFT_eSPI by Bodmer, WiFi (built-in), SD (built-in)
#define ILI9341_DRIVER // TFT_MISO 12 — NICHT definieren! IO12 LOW beim Boot = ESP32 startet nicht #define TFT_MOSI 13 / TFT_SCLK 14 #define TFT_CS 15 / TFT_DC 2 / TFT_BL 21 #define TOUCH_CS 33 #define SPI_FREQUENCY 55000000
Edit WiFi credentials in purplnova_dashboard.ino, upload, done.
MIT — do whatever you want with it.