Initial Setup
This commit is contained in:
commit
7cdb899e01
59
.gitignore
vendored
Normal file
59
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
.pio
|
||||||
|
.vscode/.browse.c_cpp.db*
|
||||||
|
.vscode/c_cpp_properties.json
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/ipch
|
||||||
|
|
||||||
|
# Build-Artefakte und kompilierte Dateien
|
||||||
|
*.elf
|
||||||
|
*.bin
|
||||||
|
*.hex
|
||||||
|
*.map
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
|
||||||
|
*.zip
|
||||||
|
|
||||||
|
# Eagle Backup-Dateien
|
||||||
|
*.s#?
|
||||||
|
*.b#?
|
||||||
|
*.l#?
|
||||||
|
|
||||||
|
# PlatformIO
|
||||||
|
.pio/
|
||||||
|
.pioenvs/
|
||||||
|
.piolibdeps/
|
||||||
|
firmware/build/
|
||||||
|
|
||||||
|
# KiCad temporaere Dateien
|
||||||
|
*.000
|
||||||
|
*.bak
|
||||||
|
*.bck
|
||||||
|
*-bak
|
||||||
|
*-cache.lib
|
||||||
|
*.kicad_pcb-bak
|
||||||
|
*.kicad_sch-bak
|
||||||
|
fp-info-cache
|
||||||
|
*-save.pro
|
||||||
|
*-save.kicad_pcb
|
||||||
|
|
||||||
|
# Generierte Fertigungsdateien (optional, je nach Workflow)
|
||||||
|
hardware/gerber/*.gbr
|
||||||
|
hardware/gerber/*.drl
|
||||||
|
|
||||||
|
# CAD temporaere Dateien
|
||||||
|
*.stl.autosave
|
||||||
|
*.step.autosave
|
||||||
|
|
||||||
|
# Halte .gitkeep Dateien
|
||||||
|
!.gitkeep
|
||||||
|
|
||||||
|
# IDE-Einstellungen
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Betriebssystem-Dateien
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
desktop.ini
|
||||||
2601
html/index.html
Normal file
2601
html/index.html
Normal file
File diff suppressed because it is too large
Load Diff
64
html_to_header.py
Normal file
64
html_to_header.py
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
import os
|
||||||
|
import gzip
|
||||||
|
|
||||||
|
html_path = "html/index.html"
|
||||||
|
header_path = "include/html.h"
|
||||||
|
|
||||||
|
# HTML-Datei lesen
|
||||||
|
with open(html_path, 'r', encoding='utf-8') as f:
|
||||||
|
html_content = f.read()
|
||||||
|
|
||||||
|
# HTML-Inhalt mit GZIP komprimieren
|
||||||
|
html_bytes = html_content.encode('utf-8')
|
||||||
|
compressed = gzip.compress(html_bytes, compresslevel=9)
|
||||||
|
|
||||||
|
# Original- und komprimierte Größe ausgeben
|
||||||
|
original_size = len(html_bytes)
|
||||||
|
compressed_size = len(compressed)
|
||||||
|
ratio = (1 - compressed_size / original_size) * 100
|
||||||
|
|
||||||
|
print(f"Original-Größe: {original_size:6d} Bytes")
|
||||||
|
print(f"Komprimierte Größe: {compressed_size:6d} Bytes")
|
||||||
|
print(f"Kompression: {ratio:5.1f}%")
|
||||||
|
|
||||||
|
# Header-Datei erstellen mit komprimierten Daten
|
||||||
|
header_content = f"""// Auto-generiert von html_to_header.py
|
||||||
|
// Original-Größe: {original_size} Bytes
|
||||||
|
// Komprimierte Größe: {compressed_size} Bytes
|
||||||
|
// Kompression: {ratio:.1f}%
|
||||||
|
|
||||||
|
#ifndef HTML_H
|
||||||
|
#define HTML_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// GZIP-komprimierte HTML-Seite
|
||||||
|
const uint8_t HTML_PAGE_GZIP[] PROGMEM = {{
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Komprimierte Bytes als Hex-Array schreiben
|
||||||
|
for i, byte in enumerate(compressed):
|
||||||
|
if i % 16 == 0:
|
||||||
|
header_content += " "
|
||||||
|
header_content += f"0x{byte:02x}"
|
||||||
|
if i < len(compressed) - 1:
|
||||||
|
header_content += ","
|
||||||
|
if (i + 1) % 16 == 0:
|
||||||
|
header_content += "\n"
|
||||||
|
else:
|
||||||
|
header_content += " "
|
||||||
|
|
||||||
|
header_content += f"""
|
||||||
|
}};
|
||||||
|
|
||||||
|
const size_t HTML_PAGE_GZIP_LEN = {compressed_size};
|
||||||
|
|
||||||
|
#endif // HTML_H
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Header-Datei schreiben
|
||||||
|
os.makedirs(os.path.dirname(header_path), exist_ok=True)
|
||||||
|
with open(header_path, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(header_content)
|
||||||
|
|
||||||
|
print(f"\nHeader-Datei erstellt: {header_path}")
|
||||||
1320
include/html.h
Normal file
1320
include/html.h
Normal file
File diff suppressed because it is too large
Load Diff
79
platformio.ini
Normal file
79
platformio.ini
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
[platformio]
|
||||||
|
default_envs = esp8266clone
|
||||||
|
|
||||||
|
[common]
|
||||||
|
lib_ldf_mode = deep
|
||||||
|
; Monitor-Einstellungen
|
||||||
|
monitor_speed = 115200
|
||||||
|
; RTS/DTR für Auto-Reset (wichtig für Clones!)
|
||||||
|
monitor_dtr = 1
|
||||||
|
monitor_rts = 1
|
||||||
|
|
||||||
|
monitor_filters =
|
||||||
|
default
|
||||||
|
time
|
||||||
|
esp8266_exception_decoder
|
||||||
|
|
||||||
|
[env]
|
||||||
|
framework = arduino
|
||||||
|
platform = espressif8266
|
||||||
|
|
||||||
|
; Bibliotheken
|
||||||
|
lib_deps =
|
||||||
|
|
||||||
|
; Build-Flags für Debug
|
||||||
|
build_flags =
|
||||||
|
-I include
|
||||||
|
-DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY
|
||||||
|
-DDEBUG_ESP_PORT=Serial
|
||||||
|
-DDEBUG_ESP_CORE=false
|
||||||
|
-DDEBUG_MODE=false ;true = Debug, false = Produktiv
|
||||||
|
-DNDEBUG
|
||||||
|
-DDEBUG_SOURCE=true
|
||||||
|
-DDEBUG_ESP_WIFI=0
|
||||||
|
-DUSE_RTC=false
|
||||||
|
-DTEST_RGB_ONLY=false
|
||||||
|
-DTEST_RGB=false
|
||||||
|
-DPOWERLOSSDETECT=false
|
||||||
|
|
||||||
|
; Monitor-Einstellungen
|
||||||
|
monitor_filters =
|
||||||
|
default
|
||||||
|
time
|
||||||
|
esp8266_exception_decoder
|
||||||
|
|
||||||
|
extra_scripts = pre:html_to_header.py
|
||||||
|
|
||||||
|
[env:esp8266clone]
|
||||||
|
board = esp12e ; ESP8266MOD = ESP-12E/F kompatibel
|
||||||
|
framework = ${env.framework}
|
||||||
|
platform = ${env.platform}
|
||||||
|
|
||||||
|
; Serial-Einstellungen
|
||||||
|
monitor_speed = ${common.monitor_speed}
|
||||||
|
|
||||||
|
upload_speed = 115200 ; Langsam für Clone-Stabilität
|
||||||
|
upload_port = COM13
|
||||||
|
|
||||||
|
; Flash-Einstellungen (sicher für alle Clones)
|
||||||
|
board_build.flash_mode = dio ; Statt qio - kompatibler!
|
||||||
|
# CPU-Frequenz auf 160MHz erhöhen
|
||||||
|
board_build.f_cpu = 160000000L
|
||||||
|
; Flash-Einstellungen (4MB Flash für Standard D1 Mini)
|
||||||
|
board_build.f_flash = 40000000L
|
||||||
|
board_build.ldscript = eagle.flash.4m2m.ld ;2 MB Sketch, 2 MB OTA kein SPIFFS
|
||||||
|
|
||||||
|
; Build-Flags für Debug
|
||||||
|
build_flags =
|
||||||
|
${env.build_flags}
|
||||||
|
;-DBRIDGE_LEDS_POS77
|
||||||
|
|
||||||
|
; Bibliotheken
|
||||||
|
lib_deps = ${env.lib_deps}
|
||||||
|
|
||||||
|
; Monitor-Einstellungen
|
||||||
|
monitor_filters = ${common.monitor_filters}
|
||||||
|
|
||||||
|
; RTS/DTR für Auto-Reset (wichtig für Clones!)
|
||||||
|
monitor_dtr = 1
|
||||||
|
monitor_rts = 1
|
||||||
279
src/main.cpp
Normal file
279
src/main.cpp
Normal file
|
|
@ -0,0 +1,279 @@
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266WebServer.h>
|
||||||
|
#include <DNSServer.h>
|
||||||
|
#include <EEPROM.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <ESP8266httpUpdate.h>
|
||||||
|
#include <Updater.h>
|
||||||
|
#include <html.h>
|
||||||
|
|
||||||
|
// Auto-generated version from build date/time
|
||||||
|
#define BUILD_DATE __DATE__
|
||||||
|
#define BUILD_TIME __TIME__
|
||||||
|
|
||||||
|
#define AP_SSID_LENGHT 14
|
||||||
|
#define AP_PASSWORD_LENGTH 17
|
||||||
|
|
||||||
|
// WiFi Zugangsdaten
|
||||||
|
const char* ssid = "DEINW_WLAN_SSID";
|
||||||
|
const char* password = "DEIN_WLAN_PASSWORT";
|
||||||
|
|
||||||
|
char AP_SSID[AP_SSID_LENGHT] = "CharGraph-01\0";
|
||||||
|
char AP_PASSWORD[AP_PASSWORD_LENGTH] = "MeinPasswort123\0";
|
||||||
|
|
||||||
|
// ════════════════════════════════════════════════════════════════
|
||||||
|
// OTA UPDATE ADRESSEN (346 bytes frei: 166-511)
|
||||||
|
// ════════════════════════════════════════════════════════════════
|
||||||
|
#define ADDR_OTA_VERSION 166 // Firmware-Version (32 bytes)
|
||||||
|
#define ADDR_OTA_BUILD_DATE 198 // Build-Datum/Zeit (20 bytes)
|
||||||
|
#define ADDR_OTA_FLAGS 218 // OTA-Status-Flags (1 byte)
|
||||||
|
|
||||||
|
#define OTA_FLAG_UPDATE_SUCCESS 0x01
|
||||||
|
#define OTA_FLAG_UPDATE_FAILED 0x02
|
||||||
|
|
||||||
|
// ════════════════════════════════════════════════════════════════
|
||||||
|
// OTA UPDATE VARIABLEN
|
||||||
|
// ════════════════════════════════════════════════════════════════
|
||||||
|
char firmwareVersion[32] = "BASIC";
|
||||||
|
bool otaInProgress = false;
|
||||||
|
int otaProgress = 0;
|
||||||
|
String otaError = "";
|
||||||
|
unsigned long otaStartTime = 0;
|
||||||
|
IPAddress apIP(192, 168, 4, 1);
|
||||||
|
|
||||||
|
|
||||||
|
// ════════════════════════════════════════════════════════════════
|
||||||
|
// NETZWERK
|
||||||
|
// ════════════════════════════════════════════════════════════════
|
||||||
|
ESP8266WebServer server(80);
|
||||||
|
DNSServer dnsServer;
|
||||||
|
const byte DNS_PORT = 53;
|
||||||
|
|
||||||
|
// ════════════════════════════════════════════════════════════════
|
||||||
|
// WEBSERVER HANDLER
|
||||||
|
// ════════════════════════════════════════════════════════════════
|
||||||
|
void handleRoot() {
|
||||||
|
// GZIP-komprimierte HTML-Seite senden
|
||||||
|
server.sendHeader("Content-Encoding", "gzip");
|
||||||
|
server.send_P(200, "text/html", (const char*)HTML_PAGE_GZIP, HTML_PAGE_GZIP_LEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void showOTAProgress(int progress, bool isError = false, bool isSuccess = false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void otaProgressCallback(size_t current, size_t total) {
|
||||||
|
if (total > 0) {
|
||||||
|
int progress = (current * 100) / total;
|
||||||
|
otaProgress = progress;
|
||||||
|
|
||||||
|
static int lastProgress = -1;
|
||||||
|
if (progress != lastProgress) {
|
||||||
|
showOTAProgress(progress);
|
||||||
|
lastProgress = progress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ════════════════════════════════════════════════════════════════
|
||||||
|
// OTA UPDATE HANDLER
|
||||||
|
// ════════════════════════════════════════════════════════════════
|
||||||
|
void handleOTAInfo() {
|
||||||
|
String json = "{";
|
||||||
|
json += "\"version\":\"" + String(firmwareVersion) + "\",";
|
||||||
|
json += "\"buildDate\":\"" + String(BUILD_DATE) + "\",";
|
||||||
|
json += "\"buildTime\":\"" + String(BUILD_TIME) + "\",";
|
||||||
|
json += "\"freeSpace\":" + String(ESP.getFreeSketchSpace()) + ",";
|
||||||
|
json += "\"sketchSize\":" + String(ESP.getSketchSize()) + ",";
|
||||||
|
json += "\"chipId\":\"" + String(ESP.getChipId(), HEX) + "\",";
|
||||||
|
json += "\"flashSize\":" + String(ESP.getFlashChipRealSize()) + ",";
|
||||||
|
json += "\"otaReady\":" + String(otaInProgress ? "false" : "true");
|
||||||
|
json += "}";
|
||||||
|
|
||||||
|
server.send(200, "application/json", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleOTAUpload() {
|
||||||
|
HTTPUpload& upload = server.upload();
|
||||||
|
|
||||||
|
if (upload.status == UPLOAD_FILE_START) {
|
||||||
|
otaInProgress = true;
|
||||||
|
otaProgress = 0;
|
||||||
|
otaError = "";
|
||||||
|
otaStartTime = millis();
|
||||||
|
|
||||||
|
WiFi.setSleepMode(WIFI_NONE_SLEEP);
|
||||||
|
showOTAProgress(0);
|
||||||
|
|
||||||
|
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
|
||||||
|
if (!Update.begin(maxSketchSpace)) {
|
||||||
|
Update.printError(Serial);
|
||||||
|
otaError = "Begin failed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (upload.status == UPLOAD_FILE_WRITE) {
|
||||||
|
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
|
||||||
|
Update.printError(Serial);
|
||||||
|
otaError = "Write failed";
|
||||||
|
} else {
|
||||||
|
size_t progress = Update.progress();
|
||||||
|
size_t total = Update.size();
|
||||||
|
if (total > 0) {
|
||||||
|
otaProgressCallback(progress, total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (upload.status == UPLOAD_FILE_END) {
|
||||||
|
if (Update.end(true)) {
|
||||||
|
showOTAProgress(100, false, true);
|
||||||
|
|
||||||
|
EEPROM.write(ADDR_OTA_FLAGS, OTA_FLAG_UPDATE_SUCCESS);
|
||||||
|
EEPROM.commit();
|
||||||
|
|
||||||
|
otaInProgress = false;
|
||||||
|
|
||||||
|
delay(3000);
|
||||||
|
ESP.restart();
|
||||||
|
} else {
|
||||||
|
Update.printError(Serial);
|
||||||
|
otaError = String(Update.getError());
|
||||||
|
showOTAProgress(100, true, false);
|
||||||
|
otaInProgress = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleOTAUploadDone() {
|
||||||
|
if (otaError.length() > 0) {
|
||||||
|
String json = "{\"success\":false,\"message\":\"" + otaError + "\"}";
|
||||||
|
server.send(500, "application/json", json);
|
||||||
|
} else {
|
||||||
|
String json = "{\"success\":true,\"message\":\"Update erfolgreich\"}";
|
||||||
|
server.send(200, "application/json", json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleOTAFromURL() {
|
||||||
|
|
||||||
|
if (!server.hasArg("url")) {
|
||||||
|
server.send(400, "application/json",
|
||||||
|
"{\"success\":false,\"message\":\"URL fehlt\"}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String firmwareURL = server.arg("url");
|
||||||
|
|
||||||
|
if (firmwareURL.length() == 0) {
|
||||||
|
server.send(400, "application/json",
|
||||||
|
"{\"success\":false,\"message\":\"URL leer\"}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
server.send(200, "application/json",
|
||||||
|
"{\"success\":true,\"message\":\"Update gestartet\"}");
|
||||||
|
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
otaInProgress = true;
|
||||||
|
otaProgress = 0;
|
||||||
|
otaError = "";
|
||||||
|
otaStartTime = millis();
|
||||||
|
|
||||||
|
WiFi.setSleepMode(WIFI_NONE_SLEEP);
|
||||||
|
showOTAProgress(0);
|
||||||
|
|
||||||
|
|
||||||
|
ESPhttpUpdate.onProgress([](int current, int total) {
|
||||||
|
otaProgressCallback(current, total);
|
||||||
|
});
|
||||||
|
|
||||||
|
ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);
|
||||||
|
|
||||||
|
WiFiClient client;
|
||||||
|
t_httpUpdate_return ret = ESPhttpUpdate.update(client, firmwareURL);
|
||||||
|
|
||||||
|
switch (ret) {
|
||||||
|
case HTTP_UPDATE_FAILED:
|
||||||
|
otaError = ESPhttpUpdate.getLastErrorString();
|
||||||
|
showOTAProgress(100, true, false);
|
||||||
|
otaInProgress = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HTTP_UPDATE_NO_UPDATES:
|
||||||
|
otaError = "No updates available";
|
||||||
|
showOTAProgress(100, true, false);
|
||||||
|
otaInProgress = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HTTP_UPDATE_OK:
|
||||||
|
showOTAProgress(100, false, true);
|
||||||
|
|
||||||
|
EEPROM.write(ADDR_OTA_FLAGS, OTA_FLAG_UPDATE_SUCCESS);
|
||||||
|
EEPROM.commit();
|
||||||
|
|
||||||
|
delay(3000);
|
||||||
|
ESP.restart();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleOTAStatus() {
|
||||||
|
String json = "{";
|
||||||
|
json += "\"inProgress\":" + String(otaInProgress ? "true" : "false") + ",";
|
||||||
|
json += "\"progress\":" + String(otaProgress) + ",";
|
||||||
|
json += "\"error\":\"" + otaError + "\",";
|
||||||
|
json += "\"elapsed\":" + String(millis() - otaStartTime);
|
||||||
|
json += "}";
|
||||||
|
|
||||||
|
server.send(200, "application/json", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleNotFound() {
|
||||||
|
Serial.println("→ handleNotFound aufgerufen");
|
||||||
|
server.sendHeader("Location", "/", true);
|
||||||
|
server.send(302, "text/plain", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
// WiFi verbinden
|
||||||
|
WiFi.mode(WIFI_AP_STA); // Dual-Mode: AP + Station
|
||||||
|
WiFi.softAP(AP_SSID, AP_PASSWORD);
|
||||||
|
delay(5000);
|
||||||
|
yield();
|
||||||
|
|
||||||
|
IPAddress apIP(192, 168, 4, 1);
|
||||||
|
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
|
||||||
|
dnsServer.start(DNS_PORT, "*", apIP);
|
||||||
|
|
||||||
|
Serial.println("");
|
||||||
|
Serial.println("");
|
||||||
|
Serial.print("Verbunden mit: ");
|
||||||
|
Serial.println(ssid);
|
||||||
|
Serial.print("IP-Adresse: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
// Root-Endpoint
|
||||||
|
server.on("/", handleRoot);
|
||||||
|
server.on("/ota/info", handleOTAInfo);
|
||||||
|
server.on("/ota/upload", HTTP_POST, handleOTAUploadDone, handleOTAUpload);
|
||||||
|
server.on("/ota/url", handleOTAFromURL);
|
||||||
|
server.on("/ota/status", handleOTAStatus);
|
||||||
|
server.onNotFound(handleNotFound);
|
||||||
|
|
||||||
|
// Server starten
|
||||||
|
server.begin();
|
||||||
|
Serial.println("HTTP-Server gestartet");
|
||||||
|
Serial.print("OTA-Upload unter: http://");
|
||||||
|
Serial.print(WiFi.localIP());
|
||||||
|
Serial.println("/update");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
dnsServer.processNextRequest();
|
||||||
|
server.handleClient();
|
||||||
|
yield();
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user