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